001    //$HeadURL: svn+ssh://jwilden@svn.wald.intevation.org/deegree/base/branches/2.5_testing/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: rbezema $
063     * 
064     * @version $Revision: 12183 $
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         */
077        public SDEUpdateHandler( SDETransaction dsTa, TableAliasGenerator aliasGenerator, SDEConnection conn ) {
078            super( dsTa.getDatastore(), aliasGenerator, conn );
079        }
080    
081        /**
082         * Performs an update operation against the associated datastore.
083         * 
084         * @param ft
085         * @param properties
086         * @param filter
087         * @return number of updated (root) feature instances
088         * @throws DatastoreException
089         */
090        public int performUpdate( MappedFeatureType ft, Map<PropertyPath, FeatureProperty> properties, Filter filter )
091                                throws DatastoreException {
092    
093            // only for statistics???
094            // FeatureId[] fids = determineAffectedFIDs( mappedFeatureType, filter );
095    
096            // process properties list
097            // TODO: has to take care about properties in related tables
098            ArrayList<MappedPropertyType> list = new ArrayList<MappedPropertyType>();
099            for ( PropertyPath path : properties.keySet() ) {
100                QualifiedName qn = path.getStep( path.getSteps() - 1 ).getPropertyName();
101                MappedPropertyType pt = (MappedPropertyType) ft.getProperty( qn );
102                if ( pt == null ) {
103                    String msg = "Internal error: unknown property type " + qn;
104                    LOG.logDebug( msg );
105                    throw new DatastoreException( msg );
106                }
107                if ( 0 < pt.getTableRelations().length ) {
108                    String msg = "Update of properties of related tables is not implemented yet " + qn;
109                    LOG.logDebug( msg );
110                    throw new DatastoreException( msg );
111                }
112                list.add( pt );
113            }
114            MappedPropertyType[] mappedPType = list.toArray( new MappedPropertyType[list.size()] );
115    
116            // prepare update
117            SDEWhereBuilder whereBuilder = datastore.getWhereBuilder( new MappedFeatureType[] { ft }, null, filter,
118                                                                      aliasGenerator );
119            Map<String, List<MappingField>> columnsMap = buildColumnsMap( ft, mappedPType, false );
120            String[] columns = columnsMap.keySet().toArray( new String[columnsMap.size()] );
121            Map<MappingField, Integer> mappingFieldsMap = buildMappingFieldMap( columns, columnsMap );
122            StringBuffer whereCondition = new StringBuffer();
123            whereBuilder.appendWhereCondition( whereCondition );
124    
125            try {
126                SeUpdate updater = new SeUpdate( conn.getConnection() );
127                updater.setState( conn.getState().getId(), new SeObjectId( SeState.SE_NULL_STATE_ID ),
128                                  SeState.SE_STATE_DIFF_NOCHECK );
129                updater.toTable( ft.getTable(), columns, whereCondition.toString() );
130                updater.setWriteMode( true );
131                SeRow row = updater.getRowToSet();
132                if ( row.hasColumns() ) {
133                    SeColumnDefinition[] cd = row.getColumns();
134                    for ( int k = 0; k < cd.length; k++ ) {
135                        LOG.logDebug( "*** col[" + k + "] name=" + cd[k].getName() + " type=" + cd[k].getType() + "/"
136                                      + typeName( cd[k].getType() ) );
137                    }
138                } else {
139                    LOG.logDebug( "*** no column definitions!!!" );
140                }
141    
142                for ( PropertyPath path : properties.keySet() ) {
143                    QualifiedName qn = path.getStep( path.getSteps() - 1 ).getPropertyName();
144                    MappedPropertyType pt = (MappedPropertyType) ft.getProperty( qn );
145                    if ( pt instanceof MappedSimplePropertyType ) {
146                        SimpleContent content = ( (MappedSimplePropertyType) pt ).getContent();
147                        if ( content instanceof MappingField ) {
148                            MappingField field = (MappingField) content;
149                            Integer resultPos = mappingFieldsMap.get( field );
150                            Object value = properties.get( path ).getValue();
151                            SDEAdapter.setRowValue( row, resultPos.intValue(), value,
152                                                    SDEAdapter.mapSQL2SDE( field.getType() ) );
153                        }
154                    } else if ( pt instanceof MappedGeometryPropertyType ) {
155                        MappingGeometryField field = ( (MappedGeometryPropertyType) pt ).getMappingField();
156                        Integer resultPos = mappingFieldsMap.get( field );
157                        SeShape value = (SeShape) datastore.convertDegreeToDBGeometry( (Geometry) properties.get( path ).getValue() );
158                        row.setShape( resultPos.intValue(), value );
159                    }
160                }
161    
162                updater.execute();
163                updater.close();
164            } catch ( SeException e ) {
165                e.printStackTrace();
166                throw new DatastoreException( "update failed", e );
167            }
168    
169            // return fids.length;
170            return 1; // don't know, how many rows are affected and don't want to query it only for
171            // statistics
172        }
173    
174        /**
175         * @param type
176         * @return the String mapped from the given type
177         */
178        public static String typeName( int type ) {
179            switch ( type ) {
180            case SeColumnDefinition.TYPE_BLOB:
181                return "BLOB";
182            case SeColumnDefinition.TYPE_CLOB:
183                return "CLOB";
184            case SeColumnDefinition.TYPE_DATE:
185                return "DATE";
186            case SeColumnDefinition.TYPE_FLOAT32:
187                return "FLOAT32";
188            case SeColumnDefinition.TYPE_FLOAT64:
189                return "FLOAT64";
190            case SeColumnDefinition.TYPE_INT16:
191                return "INT16";
192            case SeColumnDefinition.TYPE_INT32:
193                return "INT32";
194            case SeColumnDefinition.TYPE_INT64:
195                return "INT64";
196            case SeColumnDefinition.TYPE_NCLOB:
197                return "NCLOB";
198            case SeColumnDefinition.TYPE_NSTRING:
199                return "NSTRING";
200            case SeColumnDefinition.TYPE_RASTER:
201                return "RASTER";
202            case SeColumnDefinition.TYPE_SHAPE:
203                return "SHAPE";
204            case SeColumnDefinition.TYPE_STRING:
205                return "STRING";
206            case SeColumnDefinition.TYPE_UUID:
207                return "UUID";
208            case SeColumnDefinition.TYPE_XML:
209                return "XML";
210            default:
211                return "???";
212            }
213        }
214    }