001: //$HeadURL$
002: /*---------------- FILE HEADER ------------------------------------------
003: This file is part of deegree.
004: Copyright (C) 2001-2008 by:
005: Department of Geography, University of Bonn
006: http://www.giub.uni-bonn.de/deegree/
007: lat/lon GmbH
008: http://www.lat-lon.de
009:
010: This library is free software; you can redistribute it and/or
011: modify it under the terms of the GNU Lesser General Public
012: License as published by the Free Software Foundation; either
013: version 2.1 of the License, or (at your option) any later version.
014: This library is distributed in the hope that it will be useful,
015: but WITHOUT ANY WARRANTY; without even the implied warranty of
016: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: Lesser General Public License for more details.
018: You should have received a copy of the GNU Lesser General Public
019: License along with this library; if not, write to the Free Software
020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021: Contact:
022:
023: Andreas Poth
024: lat/lon GmbH
025: Aennchenstr. 19
026: 53177 Bonn
027: Germany
028: E-Mail: poth@lat-lon.de
029:
030: Prof. Dr. Klaus Greve
031: Department of Geography
032: University of Bonn
033: Meckenheimer Allee 166
034: 53115 Bonn
035: Germany
036: E-Mail: greve@giub.uni-bonn.de
037: ---------------------------------------------------------------------------*/
038:
039: package org.deegree.tools.raster;
040:
041: import static java.io.File.separator;
042:
043: import java.io.File;
044: import java.io.FileOutputStream;
045: import java.io.IOException;
046: import java.io.PrintStream;
047: import java.net.URI;
048: import java.net.URISyntaxException;
049: import java.net.URL;
050: import java.security.InvalidParameterException;
051: import java.sql.Connection;
052: import java.sql.PreparedStatement;
053: import java.sql.SQLException;
054: import java.sql.Statement;
055: import java.util.Arrays;
056: import java.util.HashMap;
057: import java.util.Iterator;
058: import java.util.List;
059: import java.util.Map;
060: import java.util.Properties;
061:
062: import javax.xml.transform.TransformerException;
063:
064: import org.deegree.datatypes.QualifiedName;
065: import org.deegree.framework.log.ILogger;
066: import org.deegree.framework.log.LoggerFactory;
067: import org.deegree.framework.util.ConvenienceFileFilter;
068: import org.deegree.framework.util.FileUtils;
069: import org.deegree.framework.util.StringTools;
070: import org.deegree.framework.xml.XMLFragment;
071: import org.deegree.framework.xml.XSLTDocument;
072: import org.deegree.io.DBConnectionPool;
073: import org.deegree.io.DBPoolException;
074: import org.deegree.io.datastore.sql.postgis.PGgeometryAdapter;
075: import org.deegree.io.dbaseapi.DBaseException;
076: import org.deegree.io.shpapi.shape_new.ShapeFile;
077: import org.deegree.io.shpapi.shape_new.ShapeFileReader;
078: import org.deegree.model.feature.Feature;
079: import org.deegree.model.feature.FeatureCollection;
080: import org.deegree.model.spatialschema.Geometry;
081: import org.deegree.model.spatialschema.GeometryException;
082: import org.xml.sax.SAXException;
083:
084: /**
085: *
086: *
087: * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
088: * @author last edited by: $Author: poth $
089: *
090: * @version $Revision: 6251 $, $Date: 2007-03-19 16:59:28 +0100 (Mo, 19 Mrz 2007) $
091: */
092: public class ImportIndexIntoDB {
093:
094: private static ILogger LOG = LoggerFactory
095: .getLogger(ImportIndexIntoDB.class);
096:
097: private static final String createPG = "create_wcs_table_template_postgis.sql";
098:
099: private static final String indexPG = "create_wcs_table_index_template_postgis.sql";
100:
101: private static final String createOrcl = "create_wcs_table_template_oracle.sql";
102:
103: private static final String indexOrcl = "create_wcs_index_table_template_oracle.sql";
104:
105: private static URI app = null;
106:
107: static {
108: try {
109: app = new URI("http://www.deegree.org/app");
110: } catch (URISyntaxException e) {
111: e.printStackTrace();
112: }
113: }
114:
115: private String table;
116:
117: private String user;
118:
119: private String pw;
120:
121: private String driver;
122:
123: private String url;
124:
125: private String rootDir;
126:
127: private File configurationFile;
128:
129: /**
130: * @param driver
131: * @param url
132: * @param user
133: * @param pw
134: * @param table
135: * @param rootDir
136: */
137: public ImportIndexIntoDB(String driver, String url, String user,
138: String pw, String table, String rootDir) {
139: this .driver = driver;
140: this .url = url;
141: this .user = user;
142: this .pw = pw;
143: this .table = table;
144: this .rootDir = rootDir;
145: ConvenienceFileFilter ff = new ConvenienceFileFilter(false,
146: "XML");
147: File dir = new File(this .rootDir);
148: configurationFile = dir.listFiles(ff)[0];
149: }
150:
151: /**
152: * main method to perform indexing of raster tile via a spatial DB
153: *
154: * @throws IOException
155: * @throws DBPoolException
156: * @throws SQLException
157: * @throws DBaseException
158: * @throws GeometryException
159: * @throws SAXException
160: * @throws TransformerException
161: */
162: public void perform() throws IOException, DBPoolException,
163: SQLException, DBaseException, GeometryException,
164: SAXException, TransformerException {
165: createTables();
166: fillIndexTable();
167: // index will be created after data has been added to increase performance
168: createIndex();
169: adaptConfiguration();
170: }
171:
172: /**
173: * fill the pyramid table with informations about the assoziation between levels and scales
174: *
175: * @param map
176: * @throws DBPoolException
177: * @throws SQLException
178: */
179: private void fillPyramidTable(Map<File, PyramidHelper> map)
180: throws DBPoolException, SQLException {
181: DBConnectionPool pool = DBConnectionPool.getInstance();
182: Connection con = pool.acquireConnection(driver, url, user, pw);
183: Iterator<PyramidHelper> iterator = map.values().iterator();
184: while (iterator.hasNext()) {
185: PyramidHelper helper = iterator.next();
186: String sql = StringTools.concat(200, "INSERT INTO ", table,
187: "_pyr (level,minscale,maxscale) values (?,?,?)");
188: PreparedStatement stmt = con.prepareStatement(sql);
189: stmt.setInt(1, helper.level);
190: stmt.setFloat(2, helper.minscale);
191: stmt.setFloat(3, helper.maxscale);
192: stmt.execute();
193: stmt.close();
194: }
195: LOG.logInfo("pyramid table filled!");
196:
197: }
198:
199: /**
200: * creates DB-indexes for pyramid and tile-index tables
201: *
202: * @throws IOException
203: * @throws DBPoolException
204: * @throws SQLException
205: */
206: private void createIndex() throws IOException, DBPoolException,
207: SQLException {
208: String template = null;
209: if (driver.toUpperCase().indexOf("ORACLE") > -1) {
210: template = indexOrcl;
211: } else if (driver.toUpperCase().indexOf("POSTGRES") > -1) {
212: template = indexPG;
213: }
214:
215: StringBuffer sb = FileUtils
216: .readTextFile(ImportIndexIntoDB.class
217: .getResource(template));
218: String tmp = StringTools.replace(sb.toString(), "$TABLE$",
219: table.toLowerCase(), true);
220: String[] sql = parseSQLStatements(tmp);
221:
222: DBConnectionPool pool = DBConnectionPool.getInstance();
223: Connection con = pool.acquireConnection(driver, url, user, pw);
224: Statement stmt = con.createStatement();
225: for (int i = 0; i < sql.length; i++) {
226: stmt.execute(sql[i]);
227: }
228: stmt.close();
229: pool.releaseConnection(con, driver, url, user, pw);
230: LOG.logInfo("indexes created!");
231:
232: }
233:
234: /**
235: * fills the index table with informations about raster tiles, their spatial extent, assigened
236: * level and assigned file
237: *
238: * @throws IOException
239: * @throws DBaseException
240: * @throws DBPoolException
241: * @throws SQLException
242: * @throws GeometryException
243: */
244: private void fillIndexTable() throws IOException, DBaseException,
245: DBPoolException, SQLException, GeometryException {
246: DBConnectionPool pool = DBConnectionPool.getInstance();
247: Connection con = pool.acquireConnection(driver, url, user, pw);
248:
249: ConvenienceFileFilter ff = new ConvenienceFileFilter(false,
250: "SHP");
251: File dir = new File(rootDir);
252: File[] files = dir.listFiles(ff);
253: Map<File, PyramidHelper> map = createLevelMap(files);
254: fillPyramidTable(map);
255: for (int i = 0; i < files.length; i++) {
256: LOG.logInfo("import: ", files[i].getAbsolutePath());
257: String tmp = files[i].getAbsolutePath();
258: tmp = tmp.substring(0, tmp.length() - 4);
259: ShapeFileReader sfr = new ShapeFileReader(tmp);
260: ShapeFile sf = sfr.read();
261: FeatureCollection fc = sf.getFeatureCollection();
262: for (int j = 0; j < fc.size(); j++) {
263: String sql = StringTools.concat(200, "INSERT INTO ",
264: table,
265: " (level, dir, file, bbox) values(?,?,?,?)");
266: PreparedStatement stmt = con.prepareStatement(sql);
267: Object[] values = createInsert(fc.getFeature(j));
268: stmt.setInt(1, map.get(files[i]).level);
269: stmt.setString(2, (String) values[1]);
270: stmt.setString(3, (String) values[2]);
271: stmt.setObject(4, values[3]);
272: stmt.execute();
273: stmt.close();
274: }
275:
276: }
277:
278: pool.releaseConnection(con, driver, url, user, pw);
279: LOG.logInfo("index table filled!");
280:
281: }
282:
283: /**
284: * creates pyramid level map; assigning each file to a level starting at 0
285: *
286: * @param files
287: * @return
288: */
289: private Map<File, PyramidHelper> createLevelMap(File[] files) {
290: PyramidHelper[] phelper = new PyramidHelper[files.length];
291: for (int i = 0; i < files.length; i++) {
292: String tmp = files[i].getName().substring(2,
293: files[i].getName().length() - 4);
294: float scale = Float.parseFloat(tmp);
295: PyramidHelper helper = new PyramidHelper();
296: helper.file = files[i];
297: helper.scale = scale;
298: phelper[i] = helper;
299: }
300: Arrays.sort(phelper);
301: Map<File, PyramidHelper> map = new HashMap<File, PyramidHelper>();
302: for (int i = 0; i < phelper.length; i++) {
303: phelper[i].level = i;
304: if (i == 0) {
305: phelper[i].minscale = 0;
306: } else {
307: phelper[i].minscale = phelper[i - 1].scale;
308: }
309: if (i == phelper.length - 1) {
310: phelper[i].maxscale = 99999999999F;
311: } else {
312: phelper[i].maxscale = phelper[i].scale;
313: }
314: map.put(phelper[i].file, phelper[i]);
315: }
316: LOG.logInfo("pyramid level assoziation:", map);
317: return map;
318: }
319:
320: /**
321: *
322: * @param feature
323: * @return values to insert for a raster tile
324: * @throws GeometryException
325: */
326: private Object[] createInsert(Feature feature)
327: throws GeometryException {
328: Object[] values = new Object[4];
329: values[1] = feature.getProperties(new QualifiedName("FOLDER",
330: app))[0].getValue();
331: values[2] = feature.getProperties(new QualifiedName("FILENAME",
332: app))[0].getValue();
333: Geometry geom = feature.getDefaultGeometryPropertyValue();
334: values[3] = PGgeometryAdapter.export(geom, -1);
335: return values;
336: }
337:
338: /**
339: * creates data and pyramid table
340: *
341: * @throws IOException
342: * @throws DBPoolException
343: * @throws SQLException
344: */
345: private void createTables() throws IOException, DBPoolException,
346: SQLException {
347: String template = null;
348: if (driver.toUpperCase().indexOf("ORACLE") > -1) {
349: template = createOrcl;
350: } else if (driver.toUpperCase().indexOf("POSTGRES") > -1) {
351: template = createPG;
352: }
353: StringBuffer sb = FileUtils
354: .readTextFile(ImportIndexIntoDB.class
355: .getResource(template));
356: String tmp = StringTools.replace(sb.toString(), "$TABLE$",
357: table.toLowerCase(), true);
358: String[] sql = parseSQLStatements(tmp);
359:
360: DBConnectionPool pool = DBConnectionPool.getInstance();
361: Connection con = pool.acquireConnection(driver, url, user, pw);
362: Statement stmt = con.createStatement();
363: for (int i = 0; i < sql.length; i++) {
364: try {
365: stmt.execute(sql[i]);
366: } catch (Exception e) {
367: LOG.logWarning(e.getMessage());
368: }
369: }
370: stmt.close();
371: pool.releaseConnection(con, driver, url, user, pw);
372: LOG.logInfo("tables created!");
373:
374: }
375:
376: /**
377: *
378: * @param tmp
379: * @return SQL statements parsed from a file/string
380: */
381: private String[] parseSQLStatements(String tmp) {
382: List<String> list = StringTools.toList(tmp, ";", false);
383: String[] sql = new String[list.size()];
384: for (int i = 0; i < sql.length; i++) {
385: sql[i] = list.get(i).trim();
386: }
387: return sql;
388: }
389:
390: /**
391: * adapts the wcs configuration for a coverage to use the created db-based index instead of a
392: * shapefile base one.
393: *
394: * @throws IOException
395: * @throws SAXException
396: * @throws TransformerException
397: */
398: private void adaptConfiguration() throws IOException, SAXException,
399: TransformerException {
400: URL url = ImportIndexIntoDB.class
401: .getResource("wcsconfiguration.xsl");
402: XSLTDocument xslt = new XSLTDocument(url);
403: XMLFragment xml = new XMLFragment(configurationFile.toURI()
404: .toURL());
405: xml = xslt.transform(xml);
406: Map<String, String> params = new HashMap<String, String>();
407: params.put("TABLE", table);
408: params.put("USER", user);
409: params.put("PASSWORD", pw);
410: params.put("DRIVER", driver);
411: params.put("URL", this .url);
412: xml = xslt
413: .transform(xml, XMLFragment.DEFAULT_URL, null, params);
414: FileOutputStream fos = new FileOutputStream(configurationFile);
415: xml.write(fos);
416: fos.close();
417: }
418:
419: /**
420: * @param args
421: */
422: public static void main(String[] args) throws Exception {
423:
424: try {
425: Properties map = new Properties();
426: for (int i = 0; i < args.length;) {
427: String first = args[i++];
428: if ("?".equals(first) || "-h".equals(first)
429: || "-help".equals(first)) {
430: printHelp();
431: System.exit(0);
432: }
433: map.put(first, args[i++]);
434: }
435:
436: // set up stderr/stdout redirection
437: String redirect = map.getProperty("-redirect");
438: if (redirect != null && redirect.equals("true")) {
439: String rootDir = map.getProperty("-rootDir");
440: File f = new File(rootDir + separator + "dbindexer.log");
441: PrintStream out = new PrintStream(new FileOutputStream(
442: f));
443: System.setOut(out);
444: System.setErr(out);
445: }
446:
447: try {
448: validate(map);
449: } catch (InvalidParameterException ipe) {
450: LOG.logError(ipe.getMessage());
451: printHelp();
452: System.exit(1);
453: }
454: LOG
455: .logDebug("Resulting commandline arguments and their values {argument=value, ...}: "
456: + map.toString());
457:
458: String table = map.getProperty("-table");
459: String user = map.getProperty("-user");
460: String pw = map.getProperty("-password");
461: String driver = map.getProperty("-driver");
462: String url = map.getProperty("-url");
463: String rootDir = map.getProperty("-rootDir");
464:
465: ImportIndexIntoDB importer = new ImportIndexIntoDB(driver,
466: url, user, pw, table, rootDir);
467: importer.perform();
468: } catch (Exception e) {
469: e.printStackTrace();
470: System.exit(1);
471: }
472:
473: System.exit(0);
474: }
475:
476: /**
477: *
478: * @param map
479: * @throws InvalidParameterException
480: */
481: private static void validate(Properties map)
482: throws InvalidParameterException {
483: if (map.getProperty("-table") == null) {
484: throw new InvalidParameterException("-table must be set");
485: }
486: if (map.getProperty("-user") == null) {
487: throw new InvalidParameterException("-user must be set");
488: }
489: if (map.getProperty("-password") == null) {
490: throw new InvalidParameterException("-password must be set");
491: }
492: if (map.getProperty("-driver") == null) {
493: throw new InvalidParameterException("-driver must be set");
494: }
495: if (map.getProperty("-url") == null) {
496: throw new InvalidParameterException("-url must be set");
497: }
498: if (map.getProperty("-rootDir") == null) {
499: throw new InvalidParameterException("-rootDir must be set");
500: }
501:
502: }
503:
504: /**
505: *
506: *
507: */
508: private static void printHelp() {
509: // TODO Auto-generated method stub
510: System.out.println("no help available at the moment");
511: }
512:
513: /**
514: *
515: *
516: *
517: * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
518: * @author last edited by: $Author: poth $
519: *
520: * @version $Revision: 6251 $, $Date: 2007-03-19 16:59:28 +0100 (Mo, 19 Mrz 2007) $
521: */
522: class PyramidHelper implements Comparable<PyramidHelper> {
523:
524: File file;
525:
526: float scale;
527:
528: float minscale;
529:
530: float maxscale;
531:
532: int level;
533:
534: /**
535: * @param o
536: */
537: public int compareTo(PyramidHelper o) {
538: if (o.scale < scale) {
539: return 1;
540: } else if (o.scale > scale) {
541: return -1;
542: }
543: return 0;
544: }
545:
546: /**
547: * @return string representation
548: */
549: public String toString() {
550: return StringTools.concat(260, file.getName(), ' ', level,
551: ' ', scale);
552: }
553:
554: }
555:
556: }
|