001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/io/datastore/sde/SDEUpdateHandler.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2006 by: M.O.S.S. Computer Grafik Systeme GmbH
006     Hohenbrunner Weg 13
007     D-82024 Taufkirchen
008     http://www.moss.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    
015     This library is distributed in the hope that it will be useful,
016     but WITHOUT ANY WARRANTY; without even the implied warranty of
017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
018     Lesser General Public License for more details.
019    
020     You should have received a copy of the GNU Lesser General Public
021     License along with this library; if not, write to the Free Software
022     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
023    
024     ---------------------------------------------------------------------------*/
025    package org.deegree.io.datastore.sde;
026    
027    import java.util.ArrayList;
028    import java.util.List;
029    import java.util.Map;
030    
031    import org.deegree.datatypes.QualifiedName;
032    import org.deegree.framework.log.ILogger;
033    import org.deegree.framework.log.LoggerFactory;
034    import org.deegree.io.datastore.DatastoreException;
035    import org.deegree.io.datastore.schema.MappedFeatureType;
036    import org.deegree.io.datastore.schema.MappedGeometryPropertyType;
037    import org.deegree.io.datastore.schema.MappedPropertyType;
038    import org.deegree.io.datastore.schema.MappedSimplePropertyType;
039    import org.deegree.io.datastore.schema.content.MappingField;
040    import org.deegree.io.datastore.schema.content.MappingGeometryField;
041    import org.deegree.io.datastore.schema.content.SimpleContent;
042    import org.deegree.io.datastore.sql.TableAliasGenerator;
043    import org.deegree.io.sdeapi.SDEAdapter;
044    import org.deegree.io.sdeapi.SDEConnection;
045    import org.deegree.model.feature.FeatureProperty;
046    import org.deegree.model.filterencoding.Filter;
047    import org.deegree.model.spatialschema.Geometry;
048    import org.deegree.ogcbase.PropertyPath;
049    
050    import com.esri.sde.sdk.client.SeColumnDefinition;
051    import com.esri.sde.sdk.client.SeException;
052    import com.esri.sde.sdk.client.SeObjectId;
053    import com.esri.sde.sdk.client.SeRow;
054    import com.esri.sde.sdk.client.SeShape;
055    import com.esri.sde.sdk.client.SeState;
056    import com.esri.sde.sdk.client.SeUpdate;
057    
058    /**
059     * Handler for <code>Update</code> operations contained in <code>Transaction</code> requests.
060     * 
061     * @author <a href="mailto:cpollmann@moss.de">Christoph Pollmann</a>
062     * @author last edited by: $Author: apoth $
063     * 
064     * @version $Revision: 7844 $
065     */
066    public class SDEUpdateHandler extends AbstractSDERequestHandler {
067    
068        private static final ILogger LOG = LoggerFactory.getLogger( SDEUpdateHandler.class );
069    
070        /**
071         * Creates a new <code>UpdateHandler</code> from the given parameters.
072         * 
073         * @param dsTa
074         * @param aliasGenerator
075         * @param conn
076         * @throws DatastoreException
077         */
078        public SDEUpdateHandler( SDETransaction dsTa, TableAliasGenerator aliasGenerator, SDEConnection conn ) {
079            super( dsTa.getDatastore(), aliasGenerator, conn );
080        }
081    
082        /**
083         * Performs an update operation against the associated datastore.
084         * 
085         * @param ft
086         * @param properties
087         * @param filter
088         * @return number of updated (root) feature instances
089         * @throws DatastoreException
090         */
091        public int performUpdate( MappedFeatureType ft, Map<PropertyPath, FeatureProperty> properties, Filter filter )
092                                throws DatastoreException {
093    
094            // only for statistics???
095            // FeatureId[] fids = determineAffectedFIDs( mappedFeatureType, filter );
096    
097            // process properties list
098            // TODO: has to take care about properties in related tables
099            ArrayList<MappedPropertyType> list = new ArrayList<MappedPropertyType>();
100            for ( PropertyPath path : properties.keySet() ) {
101                QualifiedName qn = path.getStep( path.getSteps() - 1 ).getPropertyName();
102                MappedPropertyType pt = (MappedPropertyType) ft.getProperty( qn );
103                if ( pt == null ) {
104                    String msg = "Internal error: unknown property type " + qn;
105                    LOG.logDebug( msg );
106                    throw new DatastoreException( msg );
107                }
108                if ( 0 < pt.getTableRelations().length ) {
109                    String msg = "Update of properties of related tables is not implemented yet " + qn;
110                    LOG.logDebug( msg );
111                    throw new DatastoreException( msg );
112                }
113                list.add( pt );
114            }
115            MappedPropertyType[] mappedPType = list.toArray( new MappedPropertyType[list.size()] );
116    
117            // prepare update
118            SDEWhereBuilder whereBuilder = datastore.getWhereBuilder( new MappedFeatureType[] { ft }, null, filter,
119                                                                      aliasGenerator );
120            Map<String, List<MappingField>> columnsMap = buildColumnsMap( ft, mappedPType, false );
121            String[] columns = columnsMap.keySet().toArray( new String[columnsMap.size()] );
122            Map mappingFieldsMap = buildMappingFieldMap( columns, columnsMap );
123            StringBuffer whereCondition = new StringBuffer();
124            whereBuilder.appendWhereCondition( whereCondition );
125    
126            try {
127                SeUpdate updater = new SeUpdate( conn.getConnection() );
128                updater.setState( conn.getState().getId(), new SeObjectId( SeState.SE_NULL_STATE_ID ),
129                                  SeState.SE_STATE_DIFF_NOCHECK );
130                updater.toTable( ft.getTable(), columns, whereCondition.toString() );
131                updater.setWriteMode( true );
132                SeRow row = updater.getRowToSet();
133                if ( row.hasColumns() ) {
134                    SeColumnDefinition[] cd = row.getColumns();
135                    for ( int k = 0; k < cd.length; k++ ) {
136                        LOG.logDebug( "*** col[" + k + "] name=" + cd[k].getName() + " type=" + cd[k].getType() + "/"
137                                      + typeName( cd[k].getType() ) );
138                    }
139                } else {
140                    LOG.logDebug( "*** no column definitions!!!" );
141                }
142    
143                for ( PropertyPath path : properties.keySet() ) {
144                    QualifiedName qn = path.getStep( path.getSteps() - 1 ).getPropertyName();
145                    MappedPropertyType pt = (MappedPropertyType) ft.getProperty( qn );
146                    if ( pt instanceof MappedSimplePropertyType ) {
147                        SimpleContent content = ( (MappedSimplePropertyType) pt ).getContent();
148                        if ( content instanceof MappingField ) {
149                            MappingField field = (MappingField) content;
150                            Integer resultPos = (Integer) mappingFieldsMap.get( field );
151                            Object value = properties.get( path ).getValue();
152                            SDEAdapter.setRowValue( row, resultPos.intValue(), value,
153                                                    SDEAdapter.mapSQL2SDE( field.getType() ) );
154                        }
155                    } else if ( pt instanceof MappedGeometryPropertyType ) {
156                        MappingGeometryField field = ( (MappedGeometryPropertyType) pt ).getMappingField();
157                        Integer resultPos = (Integer) mappingFieldsMap.get( field );
158                        SeShape value = (SeShape) datastore.convertDegreeToDBGeometry( (Geometry) properties.get( path ).getValue() );
159                        row.setShape( resultPos.intValue(), value );
160                    }
161                }
162    
163                updater.execute();
164                updater.close();
165            } catch ( SeException e ) {
166                e.printStackTrace();
167                throw new DatastoreException( "update failed", e );
168            }
169    
170            // return fids.length;
171            return 1; // don't know, how many rows are affected and don't want to query it only for
172            // statistics
173        }
174    
175        public static String typeName( int type ) {
176            switch ( type ) {
177            case SeColumnDefinition.TYPE_BLOB:
178                return "BLOB";
179            case SeColumnDefinition.TYPE_CLOB:
180                return "CLOB";
181            case SeColumnDefinition.TYPE_DATE:
182                return "DATE";
183            case SeColumnDefinition.TYPE_FLOAT32:
184                return "FLOAT32";
185            case SeColumnDefinition.TYPE_FLOAT64:
186                return "FLOAT64";
187            case SeColumnDefinition.TYPE_INT16:
188                return "INT16";
189            case SeColumnDefinition.TYPE_INT32:
190                return "INT32";
191            case SeColumnDefinition.TYPE_INT64:
192                return "INT64";
193            case SeColumnDefinition.TYPE_NCLOB:
194                return "NCLOB";
195            case SeColumnDefinition.TYPE_NSTRING:
196                return "NSTRING";
197            case SeColumnDefinition.TYPE_RASTER:
198                return "RASTER";
199            case SeColumnDefinition.TYPE_SHAPE:
200                return "SHAPE";
201            case SeColumnDefinition.TYPE_STRING:
202                return "STRING";
203            case SeColumnDefinition.TYPE_UUID:
204                return "UUID";
205            case SeColumnDefinition.TYPE_XML:
206                return "XML";
207            default:
208                return "???";
209            }
210        }
211    }