001: /*
002: * This file is part of the GeOxygene project source files.
003: *
004: * GeOxygene aims at providing an open framework which implements OGC/ISO specifications for
005: * the development and deployment of geographic (GIS) applications. It is a open source
006: * contribution of the COGIT laboratory at the Institut Géographique National (the French
007: * National Mapping Agency).
008: *
009: * See: http://oxygene-project.sourceforge.net
010: *
011: * Copyright (C) 2005 Institut Géographique National
012: *
013: * This library is free software; you can redistribute it and/or modify it under the terms
014: * of the GNU Lesser General Public License as published by the Free Software Foundation;
015: * either version 2.1 of the License, or any later version.
016: *
017: * This library is distributed in the hope that it will be useful, but WITHOUT ANY
018: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
019: * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
020: *
021: * You should have received a copy of the GNU Lesser General Public License along with
022: * this library (see file LICENSE if present); if not, write to the Free Software
023: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024: *
025: */
026:
027: package fr.ign.cogit.geoxygene.datatools.postgis;
028:
029: import java.io.File;
030: import java.sql.Connection;
031: import java.sql.ResultSet;
032: import java.sql.Statement;
033: import java.util.Iterator;
034: import java.util.List;
035:
036: import org.apache.ojb.broker.core.PersistenceBrokerHandle;
037: import org.apache.ojb.broker.core.PoolablePersistenceBroker;
038: import org.apache.ojb.broker.metadata.DescriptorRepository;
039: import org.apache.ojb.broker.metadata.MetadataManager;
040: import org.apache.ojb.odmg.HasBroker;
041: import org.odmg.DList;
042: import org.odmg.OQLQuery;
043: import org.postgresql.PGConnection;
044:
045: import fr.ign.cogit.geoxygene.datatools.Geodatabase;
046: import fr.ign.cogit.geoxygene.datatools.ojb.GeOxygenePersistenceBrokerImpl;
047: import fr.ign.cogit.geoxygene.datatools.ojb.GeodatabaseOjb;
048: import fr.ign.cogit.geoxygene.feature.FT_Feature;
049: import fr.ign.cogit.geoxygene.feature.FT_FeatureCollection;
050: import fr.ign.cogit.geoxygene.spatial.geomroot.GM_Object;
051:
052: /**
053: * Implementation d'une Geodatabase
054: * utilisant OJB comme mappeur
055: * et Postgis comme SGBDR geographique.
056: *
057: * @author Thierry Badard & Arnaud Braun
058: * @version 1.1
059: */
060:
061: public class GeodatabaseOjbPostgis extends GeodatabaseOjb implements
062: Geodatabase {
063:
064: /** Constructeur direct. */
065: public GeodatabaseOjbPostgis() {
066: super ();
067: updateConnection();
068: initGeomMetadata();
069: }
070:
071: /** Constructeur en specialisant GeodatabaseOjb.
072: * Usage interne, appele par GeodatabaseOjbFactory. */
073: public GeodatabaseOjbPostgis(GeodatabaseOjb ojb) {
074: _conn = ojb.getConnection();
075: _odmg = ojb.getODMGImplementation();
076: _db = ojb.getODMGDatabase();
077: _tx = ojb.getODMGTransaction();
078: _metadataList = ojb.getMetadata();
079: updateConnection();
080: initGeomMetadata();
081: }
082:
083: /** Ajoute les types de donnees geometriques a la connection Postgres. */
084: private void updateConnection() {
085: try {
086: /* pgConn.addDataType(String, String) is deprecated in version 1.0.x of the Postgresql JDBC driver.
087: * This modification breaks compatibility with version 0.x of PostGIS. */
088:
089: PGConnection pgConn = (PGConnection) _conn;
090: //pgConn.addDataType("geometry","org.postgis.PGgeometry");
091: pgConn
092: .addDataType("geometry",
093: org.postgis.PGgeometry.class);
094: //pgConn.addDataType("box3d","org.postgis.PGbox3d");
095: pgConn.addDataType("box3d", org.postgis.PGbox3d.class);
096:
097: //System.out.println(pgConn.toString());
098:
099: } catch (Exception e) {
100: e.printStackTrace();
101: }
102: }
103:
104: /** Renseigne l'attribut _metadataList.
105: * Attention pour POSTGIS, l'emprise et la tolerance ne sont pas renseignes. */
106: private void initGeomMetadata() {
107: PostgisSpatialQuery.initGeomMetadata(_metadataList, _conn);
108: }
109:
110: /** Charge tous les FT_Feature de la classe theClass intersectant le GM_Object geom, dans la classe FT_FeatureCollection.
111: A appeler a l'interieur d'une transaction ouverte.
112: La classe theClass doit etre une sous-classe de FT_Feature, sinon renvoie une liste vide. */
113: public FT_FeatureCollection loadAllFeatures(Class featureClass,
114: GM_Object geom) {
115: FT_FeatureCollection result = new FT_FeatureCollection();
116: if ((FT_Feature.class).isAssignableFrom(featureClass)) {
117: // on cherche la liste des identifiants
118: List idList = PostgisSpatialQuery.loadAllFeatures(this ,
119: featureClass, geom);
120: // charge tous les objets dont on a trouve l'identifiant
121: if (idList.size() > 0) {
122: String query = createInQuery(idList, featureClass
123: .getName());
124: OQLQuery oqlQuery = _odmg.newOQLQuery();
125: try {
126: oqlQuery.create(query);
127: DList list = (DList) oqlQuery.execute();
128: Iterator iter = list.iterator();
129: while (iter.hasNext()) {
130: FT_Feature feature = (FT_Feature) iter.next();
131: result.add(feature);
132: }
133: } catch (Exception e) {
134: e.printStackTrace();
135: }
136: }
137: } else {
138: System.out
139: .println("loadAllFeatures() : La classe passee en parametre n'est pas une sous-classe de FT_Feature");
140: }
141: return result;
142:
143: }
144:
145: /** Charge tous les FT_Feature de la classe theClass intersectant le GM_Object geom, dans la classe featureListClass.
146: A appeler a l'interieur d'une transaction ouverte.
147: La classe theClass doit etre une sous-classe de FT_Feature, sinon renvoie une liste vide.
148: La classe featureListClass doit etre un sous classe de FT_FeatureCollection.*/
149: public Object loadAllFeatures(Class featureClass,
150: Class featureListClass, GM_Object geom) {
151: Object result = null;
152: try {
153: result = featureListClass.newInstance();
154: } catch (Exception e) {
155: e.printStackTrace();
156: }
157: if ((FT_Feature.class).isAssignableFrom(featureClass)) {
158: // on cherche la liste des identifiants
159: List idList = PostgisSpatialQuery.loadAllFeatures(this ,
160: featureClass, geom);
161: // charge tous les objets dont on a trouve l'identifiant
162: if (idList.size() > 0) {
163: String query = createInQuery(idList, featureClass
164: .getName());
165: OQLQuery oqlQuery = _odmg.newOQLQuery();
166: try {
167: oqlQuery.create(query);
168: DList list = (DList) oqlQuery.execute();
169: Iterator iter = list.iterator();
170: while (iter.hasNext()) {
171: FT_Feature feature = (FT_Feature) iter.next();
172: result.getClass().getMethod("add",
173: new Class[] { FT_Feature.class })
174: .invoke(result,
175: new Object[] { feature });
176: }
177: } catch (Exception e) {
178: e.printStackTrace();
179: }
180: }
181: } else {
182: System.out
183: .println("loadAllFeatures() : La classe passee en parametre n'est pas une sous-classe de FT_Feature");
184: }
185: return result;
186: }
187:
188: /** Charge tous les FT_Feature de la classe theClass a une distance dist du GM_Object geom, dans la classe FT_FeatureCollection.
189: Si geom est la geometrie d'un FT_Feature de theClass, alors ce FT_Feature appartiendra au resultat.
190: A appeler a l'interieur d'une transaction ouverte.
191: La classe theClass doit etre une sous-classe de FT_Feature, sinon renvoie une liste vide.*/
192: public FT_FeatureCollection loadAllFeatures(Class featureClass,
193: GM_Object geom, double dist) {
194: FT_FeatureCollection result = new FT_FeatureCollection();
195: if ((FT_Feature.class).isAssignableFrom(featureClass)) {
196: // on cherche la liste des identifiants
197: List idList = PostgisSpatialQuery.loadAllFeatures(this ,
198: featureClass, geom, dist);
199: // charge tous les objets dont on a trouve l'identifiant
200: if (idList.size() > 0) {
201: String query = createInQuery(idList, featureClass
202: .getName());
203: OQLQuery oqlQuery = _odmg.newOQLQuery();
204: try {
205: oqlQuery.create(query);
206: DList list = (DList) oqlQuery.execute();
207: Iterator iter = list.iterator();
208: while (iter.hasNext()) {
209: FT_Feature feature = (FT_Feature) iter.next();
210: result.add(feature);
211: }
212: } catch (Exception e) {
213: e.printStackTrace();
214: }
215: }
216: } else {
217: System.out
218: .println("loadAllFeatures() : La classe passee en parametre n'est pas une sous-classe de FT_Feature");
219: }
220: return result;
221: }
222:
223: /** Charge tous les FT_Feature de la classe theClass a une distance dist du GM_Object geom, dans la classe featureListClass.
224: Si geom est la geometrie d'un FT_Feature de theClass, alors ce FT_Feature appartiendra au resultat.
225: A appeler a l'interieur d'une transaction ouverte.
226: La classe theClass doit etre une sous-classe de FT_Feature, sinon renvoie une liste vide.
227: La classe featureListClass doit etre un sous classe de FT_FeatureCollection.*/
228: public Object loadAllFeatures(Class featureClass,
229: Class featureListClass, GM_Object geom, double dist) {
230: Object result = null;
231: try {
232: result = (FT_FeatureCollection) featureListClass
233: .newInstance();
234: } catch (Exception e) {
235: e.printStackTrace();
236: }
237: if ((FT_Feature.class).isAssignableFrom(featureClass)) {
238: // on cherche la liste des identifiants
239: List idList = PostgisSpatialQuery.loadAllFeatures(this ,
240: featureClass, geom, dist);
241: // charge tous les objets dont on a trouve l'identifiant
242: if (idList.size() > 0) {
243: String query = createInQuery(idList, featureClass
244: .getName());
245: OQLQuery oqlQuery = _odmg.newOQLQuery();
246: try {
247: oqlQuery.create(query);
248: DList list = (DList) oqlQuery.execute();
249: Iterator iter = list.iterator();
250: while (iter.hasNext()) {
251: FT_Feature feature = (FT_Feature) iter.next();
252: result.getClass().getMethod("add",
253: new Class[] { FT_Feature.class })
254: .invoke(result,
255: new Object[] { feature });
256: }
257: } catch (Exception e) {
258: e.printStackTrace();
259: }
260: }
261: } else {
262: System.out
263: .println("loadAllFeatures() : La classe passee en parametre n'est pas une sous-classe de FT_Feature");
264: }
265: return result;
266: }
267:
268: /** Cree une requete pour permettre de charger tous les objets a partir d'une liste d'identifants.
269: * Usage interne. */
270: private String createInQuery(List idList, String className) {
271: String result = "select x from " + className + " where id in (";
272: StringBuffer strbuff = new StringBuffer(result);
273: Iterator i = idList.iterator();
274: while (i.hasNext()) {
275: int k = ((Number) i.next()).intValue();
276: strbuff.append(k);
277: strbuff.append(",");
278: }
279: result = strbuff.toString();
280: result = result.substring(0, result.length() - 1);
281: result = result + ")";
282: return result;
283: }
284:
285: /** Ne fonctionne pas sous POSTGIS. */
286: public void mbr(Class clazz) {
287: System.out
288: .println("GeodatabaseOjbPostgis::mbr() : inutile sous Postgis !");
289: }
290:
291: /** Calcule un index spatial sur la table mappee avec la classe (R-Tree).
292: La classe doit heriter de FT_Feature, la table doit contenir une geometrie. */
293: public void spatialIndex(Class clazz) {
294: PostgisSpatialQuery.spatialIndex(this , clazz);
295: }
296:
297: /** Renvoie le nombre d'objets persistants de la classe theClass.
298: A appeler a l'interieur d'une transaction ouverte. */
299: public int countObjects(Class theClass) {
300: String tableName = getMetadata(theClass).getTableName();
301: String query = "select count(*) from " + tableName;
302: Number nn = null;
303: try {
304: Connection conn = getConnection();
305: Statement stm = conn.createStatement();
306: ResultSet rs = (ResultSet) stm.executeQuery(query);
307: while (rs.next())
308: nn = (Number) rs.getObject(1);
309: stm.close();
310: } catch (Exception e) {
311: e.printStackTrace();
312: }
313: return nn.intValue();
314: }
315:
316: /** Renvoie l'identifiant maximum de la classe theClass.
317: ATTENTION : La classe passee en parametre doit avoir un champ "id" de type int (marche pour les FT_Feature).
318: A appeler a l'interieur d'une transaction ouverte. */
319: public int maxId(Class theClass) {
320: String idColumnName = getMetadata(theClass).getIdColumnName();
321: String tableName = getMetadata(theClass).getTableName();
322: String query = "select max(" + idColumnName + ") from "
323: + tableName;
324: Number nn = null;
325: try {
326: Connection conn = getConnection();
327: Statement stm = conn.createStatement();
328: ResultSet rs = (ResultSet) stm.executeQuery(query);
329: while (rs.next())
330: nn = (Number) rs.getObject(1);
331: stm.close();
332: } catch (Exception e) {
333: e.printStackTrace();
334: }
335: return nn.intValue();
336: }
337:
338: /** Renvoie l'identifiant minimum de la classe theClass.
339: ATTENTION : La classe passee en parametre doit avoir un champ "id" de type int (marche pour les FT_Feature).
340: A appeler a l'interieur d'une transaction ouverte. */
341: public int minId(Class theClass) {
342: String idColumnName = getMetadata(theClass).getIdColumnName();
343: String tableName = getMetadata(theClass).getTableName();
344: String query = "select min(" + idColumnName + ") from "
345: + tableName;
346: Number nn = null;
347: try {
348: Connection conn = getConnection();
349: Statement stm = conn.createStatement();
350: ResultSet rs = (ResultSet) stm.executeQuery(query);
351: while (rs.next())
352: nn = (Number) rs.getObject(1);
353: stm.close();
354: } catch (Exception e) {
355: e.printStackTrace();
356: }
357: return nn.intValue();
358: }
359:
360: /** renvoie le type de SGBD associe. */
361: public int getDBMS() {
362: return Geodatabase.POSTGIS;
363: }
364:
365: /** Utilise par EsayLoader pour recharger un fichier de mapping qui a ete modifie. */
366: public void refreshRepository(File newRepository) throws Exception {
367: MetadataManager mm = MetadataManager.getInstance();
368: DescriptorRepository rd = mm
369: .readDescriptorRepository(newRepository.getPath());
370: mm.setDescriptor(rd, true);
371: begin();
372: PersistenceBrokerHandle pbh = (PersistenceBrokerHandle) ((HasBroker) _tx)
373: .getBroker();
374: PoolablePersistenceBroker ppb = (PoolablePersistenceBroker) pbh
375: .getDelegate();
376: GeOxygenePersistenceBrokerImpl pbi = (GeOxygenePersistenceBrokerImpl) ppb
377: .getDelegate();
378: pbi.refresh();
379: commit();
380: initMetadata();
381: initGeomMetadata();
382: }
383:
384: }
|