001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/io/sdeapi/Transaction.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2007 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53115 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     
043     ---------------------------------------------------------------------------*/
044    package org.deegree.io.sdeapi;
045    
046    import java.io.ByteArrayInputStream;
047    import java.util.ArrayList;
048    import java.util.Date;
049    import java.util.HashMap;
050    import java.util.Iterator;
051    import java.util.Vector;
052    
053    import org.deegree.framework.log.ILogger;
054    import org.deegree.framework.log.LoggerFactory;
055    import org.deegree.framework.util.TimeTools;
056    import org.deegree.model.spatialschema.Geometry;
057    
058    import com.esri.sde.sdk.client.SeColumnDefinition;
059    import com.esri.sde.sdk.client.SeConnection;
060    import com.esri.sde.sdk.client.SeCoordinateReference;
061    import com.esri.sde.sdk.client.SeDelete;
062    import com.esri.sde.sdk.client.SeException;
063    import com.esri.sde.sdk.client.SeExtent;
064    import com.esri.sde.sdk.client.SeInsert;
065    import com.esri.sde.sdk.client.SeLayer;
066    import com.esri.sde.sdk.client.SeRow;
067    import com.esri.sde.sdk.client.SeShape;
068    import com.esri.sde.sdk.client.SeTable;
069    import com.esri.sde.sdk.client.SeUpdate;
070    
071    /**
072     * the class offers access to the transactional behavior of the a connection to ArcSDE
073     * 
074     * @version $Revision: 7011 $ $Date: 2007-05-09 18:53:11 +0200 (Mi, 09 Mai 2007) $
075     */
076    public class Transaction {
077    
078        private static ILogger LOG = LoggerFactory.getLogger( Transaction.class );
079    
080        // Connection to SDE
081        private SeConnection conn = null;
082    
083        // Currently opened Layer and associated Table
084        private SeLayer layer = null;
085    
086        private HashMap<String, SeColumnDefinition> colDefs = null;
087    
088        private ArrayList<SeColumnDefinition> colDefsList = null;
089    
090        // Current Spatial Filter - a BoundingBox
091        private SeShape spatialFilter = null;
092    
093        /**
094         * Creates a new SpatialQuery object.
095         * 
096         * @param server
097         * @param port
098         * @param database
099         * @param user
100         * @param password
101         * 
102         * @throws SeException
103         */
104        public Transaction( String server, int port, String database, String user, String password ) throws SeException {
105            openConnection( server, port, database, user, password );
106        }
107    
108        /**
109         * Connect to the ArcSDE server <br>
110         * throws SeException
111         */
112        public void openConnection( String server, int port, String database, String user, String password )
113                                throws SeException {
114    
115            conn = new SeConnection( server, port, database, user, password );
116    
117        }
118    
119        /**
120         * Close the current connection to the ArcSDE server <br>
121         * throws SeException
122         */
123        public void closeConnection()
124                                throws SeException {
125            conn.close();
126        }
127    
128        /**
129         * Set a SDE layer to work on and appropriate table <br>
130         * throws SeException
131         */
132        public void setLayer( String layername )
133                                throws SeException {
134    
135            Vector layerList = conn.getLayers();
136            String spatialCol = "";
137    
138            for ( int i = 0; i < layerList.size(); i++ ) {
139                SeLayer layer = (SeLayer) layerList.elementAt( i );
140    
141                if ( layer.getQualifiedName().trim().equalsIgnoreCase( layername ) ) {
142                    spatialCol = layer.getSpatialColumn();
143                    break;
144                }
145            }
146    
147            layer = new SeLayer( conn, layername, spatialCol );
148            SeTable table = new SeTable( conn, layer.getQualifiedName() );
149            SeColumnDefinition[] cols = table.describe();
150            colDefs = new HashMap<String, SeColumnDefinition>();
151            colDefsList = new ArrayList<SeColumnDefinition>();
152            for ( int i = 0; i < cols.length; i++ ) {
153                colDefs.put( cols[i].getName(), cols[i] );
154                colDefsList.add( cols[i] );
155            }
156    
157        }
158    
159        /**
160         * Set a SpatialFilter to Query (BoundingBox) <br>
161         * throws SeException
162         */
163        public void setSpatialFilter( double minx, double miny, double maxx, double maxy )
164                                throws SeException {
165    
166            spatialFilter = new SeShape( layer.getCoordRef() );
167    
168            SeExtent extent = new SeExtent( minx, miny, maxx, maxy );
169            spatialFilter.generateRectangle( extent );
170    
171        }
172    
173        /**
174         * inserts a feature into the ArcSDE
175         * 
176         * @param inRow
177         *            feature/row to be inserted
178         * 
179         * @throws SeException
180         */
181        public void insertFeature( HashMap inRow )
182                                throws SeException, DeegreeSeException {
183    
184            ArrayList<String> list = new ArrayList<String>();
185            // get all fields of the row where the values are not null
186            for ( int i = 0; i < colDefsList.size(); i++ ) {
187                SeColumnDefinition cd = colDefsList.get( i );
188                if ( inRow.get( cd.getName() ) != null || inRow.get( cd.getName().toUpperCase() ) != null ) {
189                    list.add( cd.getName() );
190                }
191            }
192            String[] columns = list.toArray( new String[list.size()] );
193    
194            SeInsert insert = null;
195            try {
196                // create an insert object
197                insert = new SeInsert( conn );
198                insert.intoTable( layer.getName(), columns );
199                insert.setWriteMode( true );
200    
201                SeRow row = insert.getRowToSet();
202                SeColumnDefinition[] cols = row.getColumns();
203    
204                // get reference system
205                SeCoordinateReference coordref = layer.getCoordRef();
206                for ( int i = 0; i < cols.length; i++ ) {
207                    Object o = inRow.get( cols[i].getName() );
208                    if ( o == null ) {
209                        o = inRow.get( cols[i].getName().toUpperCase() );
210                    }
211                    if ( o != null ) {
212                        int type = cols[i].getType();
213                        row = setValue( row, i, type, o, coordref );
214                    }
215                }
216                // perform insert operation
217                insert.execute();
218                insert.flushBufferedWrites();
219            } catch ( SeException e ) {
220                throw e;
221            } finally {
222                // Making sure the insert stream was closed. If the stream isn't closed,
223                // the resources used by the stream will be held/locked by the stream
224                // until the associated connection is closed.
225                try {
226                    insert.close();
227                } catch ( SeException se ) {
228                    se.printStackTrace();
229                }
230            }
231    
232        }
233    
234        /**
235         * fills the passed row with the also passed value considering its type
236         * 
237         * @param row
238         *            SDE row to insert
239         * @param pos
240         *            position where to set the value in the row
241         * @param type
242         *            value type
243         * @param value
244         *            value to insert
245         */
246        private SeRow setValue( SeRow row, int pos, int type, Object value, SeCoordinateReference crs )
247                                throws SeException, DeegreeSeException {
248    
249            switch ( type ) {
250            case SeColumnDefinition.TYPE_BLOB: {
251                if ( value == null ) {
252                    row.setBlob( pos, null );
253                } else {
254                    row.setBlob( pos, (ByteArrayInputStream) value );
255                }
256                break;
257            }
258            case SeColumnDefinition.TYPE_DATE: {
259                if ( value != null && value instanceof String ) {
260                    value = TimeTools.createCalendar( (String) value ).getTime();
261                }
262                row.setDate( pos, (Date) value );
263                break;
264            }
265            case SeColumnDefinition.TYPE_FLOAT64: {
266                if ( value != null && value instanceof String ) {
267                    value = new Double( (String) value );
268                }
269                row.setDouble( pos, (Double) value );
270                break;
271            }
272            case SeColumnDefinition.TYPE_FLOAT32: {
273                if ( value != null && value instanceof String ) {
274                    value = new Float( (String) value );
275                }
276                row.setFloat( pos, (Float) value );
277                break;
278            }
279            case SeColumnDefinition.TYPE_INT32: {
280                if ( value != null && value instanceof String ) {
281                    value = new Integer( (String) value );
282                }
283                row.setInteger( pos, (Integer) value );
284                break;
285            }
286            case SeColumnDefinition.TYPE_RASTER: {
287                row.setBlob( pos, (ByteArrayInputStream) value );
288                break;
289            }
290            case SeColumnDefinition.TYPE_SHAPE: {
291                // TODO
292                /*
293                 * if (value != null && value instanceof String) { // if value is a string try to
294                 * convert it into GML try { value = GMLGeometryAdapter.wrap( (String)value ); } catch
295                 * (Exception e) { throw new SeInvalidShapeException( "the passed value "+ "isn't a GML
296                 * geometry\n" + e); } } if (value != null && value instanceof GMLGeometry) { // if
297                 * value is a GML convert it into a deegree geometry try { value =
298                 * GMLGeometryAdapter.wrap( ((GMLGeometry)value).getAsElement() ); } catch (Exception e) {
299                 * throw new SeInvalidShapeException( "the passed value/GML "+ "can't be transformed "+ "
300                 * to a deegree geometry\n" + e); } }
301                 */
302                try {
303                    if ( value != null ) {
304                        SeShape shp = SDEAdapter.export( (Geometry) value, crs );
305                        row.setShape( pos, shp );
306                    } else {
307                        row.setShape( pos, null );
308                    }
309                } catch ( Exception e ) {
310                    throw new DeegreeSeException( "the passed geometry can't  " + "be transformed to a SeShape\n" + e );
311                }
312                break;
313            }
314            case SeColumnDefinition.TYPE_INT16: {
315                if ( value != null && value instanceof String ) {
316                    value = new Short( (String) value );
317                }
318                row.setShort( pos, (Short) value );
319                break;
320            }
321            case SeColumnDefinition.TYPE_STRING: {
322                row.setString( pos, (String) value );
323                break;
324            }
325            }
326    
327            return row;
328        }
329    
330        /**
331         * updates a feature of the ArcSDE
332         * 
333         * @param inRow
334         *            update data
335         * @param where
336         *            none spatial condtions to limit the targeted rows
337         * @param extent
338         *            spatial condtion to limit the targeted rows (not considered yet)
339         * 
340         * @throws SeException
341         */
342        public void updateFeature( HashMap inRow, String where, Geometry extent )
343                                throws SeException, DeegreeSeException {
344    
345            ArrayList<String> list = new ArrayList<String>();
346    
347            // get all fields of the row where the values are not null
348            Iterator iterator = inRow.keySet().iterator();
349            while ( iterator.hasNext() ) {
350                Object o = iterator.next();
351                if ( o != null ) {
352                    list.add( (String) o );
353                }
354            }
355            String[] columns = list.toArray( new String[list.size()] );
356    
357            // get rows to be updated
358            // SeQuery query = new SeQuery( conn, columns, sqlCons );
359            SeUpdate update = new SeUpdate( conn );
360            SeTable table = new SeTable( conn, layer.getQualifiedName() );
361            // TODO use also spatial conditions
362            update.toTable( table.getName(), columns, where.trim() );
363            update.setWriteMode( true );
364    
365            SeRow row = update.getRowToSet();
366            SeCoordinateReference coordref = layer.getCoordRef();
367    
368            if ( row != null ) {
369                // while ( row != null ) {
370                for ( int i = 0; i < columns.length; i++ ) {
371                    int type = colDefs.get( columns[i] ).getType();
372                    row = setValue( row, i, type, inRow.get( columns[i] ), coordref );
373                }
374                // row = update.getRowToSet();
375                // }
376                update.execute();
377            } else {
378                LOG.logWarning( "No rows fetched/updated" );
379            }
380    
381            update.close();
382    
383        }
384    
385        /**
386         * deletes a feature from the ArcSDE
387         * 
388         * @param where
389         *            none spatial condtions to limit the targeted rows
390         * @param extent
391         *            spatial condtion to limit the targeted rows (not considered yet)
392         * 
393         * @throws SeException
394         */
395        public void deleteFeature( String where, Geometry extent )
396                                throws SeException {
397    
398            // TODO use also spatial conditions
399            SeDelete delete = new SeDelete( conn );
400            delete.fromTable( layer.getQualifiedName(), where );
401            delete.close();
402    
403        }
404    
405    }