//$Header: /home/deegree/jail/deegreerepository/deegree/src/org/deegree/io/datastore/sde/SDEInsertHandler.java,v 1.8 2006/09/26 16:44:51 mschneider Exp $
/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2006 by: M.O.S.S. Computer Grafik Systeme GmbH
Hohenbrunner Weg 13
D-82024 Taufkirchen
http://www.moss.de/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
---------------------------------------------------------------------------*/
package org.deegree.io.datastore.sde;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.deegree.datatypes.Types;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.io.datastore.DatastoreException;
import org.deegree.io.datastore.FeatureId;
import org.deegree.io.datastore.TransactionException;
import org.deegree.io.datastore.idgenerator.FeatureIdAssigner;
import org.deegree.io.datastore.idgenerator.IdGenerationException;
import org.deegree.io.datastore.idgenerator.ParentIDGenerator;
import org.deegree.io.datastore.schema.MappedFeaturePropertyType;
import org.deegree.io.datastore.schema.MappedFeatureType;
import org.deegree.io.datastore.schema.MappedGMLSchema;
import org.deegree.io.datastore.schema.MappedGeometryPropertyType;
import org.deegree.io.datastore.schema.MappedPropertyType;
import org.deegree.io.datastore.schema.MappedSimplePropertyType;
import org.deegree.io.datastore.schema.TableRelation;
import org.deegree.io.datastore.schema.content.MappingField;
import org.deegree.io.datastore.schema.content.SimpleContent;
import org.deegree.io.datastore.sql.transaction.FeatureRow;
import org.deegree.io.datastore.sql.transaction.InsertRow;
import org.deegree.io.datastore.sql.transaction.InsertRow.InsertField;
import org.deegree.io.sdeapi.SDEAdapter;
import org.deegree.model.feature.Feature;
import org.deegree.model.feature.FeatureProperty;
import org.deegree.model.feature.schema.FeaturePropertyType;
import org.deegree.model.feature.schema.FeatureType;
import org.deegree.model.feature.schema.GeometryPropertyType;
import org.deegree.model.feature.schema.SimplePropertyType;
import org.deegree.model.spatialschema.Geometry;
import com.esri.sde.sdk.client.SeException;
import com.esri.sde.sdk.client.SeInsert;
import com.esri.sde.sdk.client.SeObjectId;
import com.esri.sde.sdk.client.SeQuery;
import com.esri.sde.sdk.client.SeRow;
import com.esri.sde.sdk.client.SeSqlConstruct;
import com.esri.sde.sdk.client.SeState;
/**
* Handler for <code>Insert</code> operations (usually contained in <code>Transaction</code>
* requests).
*
* @author <a href="mailto:cpollmann@moss.de">Christoph Pollmann</a>
* @author last edited by: $Author: mschneider $
*
* @version $Revision: 1.8 $
*/
public class SDEInsertHandler extends AbstractSDERequestHandler {
private static final ILogger LOG = LoggerFactory.getLogger( SDEInsertHandler.class );
// features that are currently being processed
private Map<FeatureId, FeatureRow> featuresInInsertion = new HashMap<FeatureId, FeatureRow>();
// contains only property rows and join table rows (but no feature rows)
private List<InsertRow> insertRows = new ArrayList<InsertRow>();
private SDETransaction dsTa;
/**
* Creates a new <code>InsertHandler</code> from the given parameters.
*
* @param dsTa
*/
public SDEInsertHandler( SDETransaction dsTa ) {
super( dsTa.getDatastore(), dsTa.getAliasGenerator(), dsTa.getConnection() );
this.dsTa = dsTa;
}
/**
* Inserts the given feature instance into the datastore.
*
* @param features
* (which have a MappedFeatureType as feature type)
* @return feature ids of inserted (root) feature instances
* @throws DatastoreException
* if the insert could not be performed
*/
public List<FeatureId> performInsert( List<Feature> features )
throws DatastoreException {
List<FeatureId> fids = new ArrayList<FeatureId>();
for ( int i = 0; i < features.size(); i++ ) {
Feature feature = features.get( i );
MappedFeatureType ft = (MappedFeatureType) feature.getFeatureType();
if ( feature.getId().startsWith( FeatureIdAssigner.EXIST_PREFIX ) ) {
String msg = "feature already exists " + feature.getName() + " id="
+ feature.getId().substring( 1 );
throw new TransactionException( msg );
}
LOG.logDebug( "Inserting root feature '" + feature.getId() + "'..." );
insertFeature( feature );
FeatureId fid = new FeatureId(
ft.getGMLId(),
new Object[] { FeatureId.removeFIDPrefix(
feature.getId(),
ft.getGMLId() ) } );
fids.add( fid );
}
// merge inserts rows that are identical (except their pks)
this.insertRows = mergeInsertRows( this.insertRows );
// add featureRows to insertRows
Iterator<FeatureRow> iter = this.featuresInInsertion.values().iterator();
while ( iter.hasNext() ) {
this.insertRows.add( iter.next() );
}
// check for cyclic fk constraints
Collection<InsertRow> cycle = InsertRow.findCycle( this.insertRows );
if ( cycle != null ) {
Iterator<InsertRow> cycleIter = cycle.iterator();
StringBuffer sb = new StringBuffer();
while ( cycleIter.hasNext() ) {
sb.append( cycleIter.next() );
if ( cycle.iterator().hasNext() ) {
sb.append( " -> " );
}
}
String msg = "ERROR_FK_CYCLE " + sb.toString();
throw new TransactionException( msg );
}
// sort the insert rows topologically
List<InsertRow> sortedInserts = InsertRow.sortInsertRows( this.insertRows );
if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
Iterator<InsertRow> iter2 = sortedInserts.iterator();
LOG.logDebug( sortedInserts.size() + " rows to be inserted: " );
while ( iter2.hasNext() ) {
LOG.logDebug( iter2.next().toString() );
}
}
executeInserts( sortedInserts );
return fids;
}
/**
* Builds the <code>InsertRows</code> that are necessary to insert the given feature instance
* (including all properties + subfeatures).
*
* @param feature
* @return
* @throws TransactionException
*/
private FeatureRow insertFeature( Feature feature )
throws TransactionException {
MappedFeatureType ft = (MappedFeatureType) feature.getFeatureType();
if ( !ft.isInsertable() ) {
String msg = "featuretype can't be inserted " + ft.getName();
throw new TransactionException( msg );
}
LOG.logDebug( "Creating InsertRow for feature with type '" + ft.getName() + "' and id: '"
+ feature.getId() + "'." );
// extract feature id column value
MappingField[] fidFields = ft.getGMLId().getIdFields();
if ( fidFields.length > 1 ) {
throw new TransactionException(
"Insertion of features with compound feature ids is not "
+ "supported." );
}
Object fidValue = null;
try {
fidValue = FeatureId.removeFIDPrefix( feature.getId(), ft.getGMLId() );
} catch ( DatastoreException e ) {
e.printStackTrace();
throw new TransactionException( e.getMessage(), e );
}
FeatureId fid = new FeatureId( ft.getGMLId(), new Object[] { fidValue } );
// check if the feature id is already being inserted (happens for cyclic features)
FeatureRow insertRow = this.featuresInInsertion.get( fid );
if ( insertRow != null ) {
return insertRow;
}
insertRow = new FeatureRow( ft.getTable() );
this.featuresInInsertion.put( fid, insertRow );
// add column value for fid (primary key)
String fidColumn = fidFields[0].getField();
insertRow.setColumn( fidColumn, fidValue, ft.getGMLId().getIdFields()[0].getType(), true );
// process properties
FeatureProperty[] properties = feature.getProperties();
for ( int i = 0; i < properties.length; i++ ) {
FeatureProperty property = properties[i];
MappedPropertyType propertyType = (MappedPropertyType) ft.getProperty( property.getName() );
if ( propertyType == null ) {
String msg = "Unknown propertytype " + property.getName();
LOG.logDebug( msg );
throw new TransactionException( msg );
}
insertProperty( ft, property, propertyType, insertRow );
}
return insertRow;
}
/**
* Builds the <code>InsertRow</code>s that are necessary to insert the given property instance
* (including all it's subfeatures).
*
* @param featureType
* parent feature type (that the property belongs to)
* @param property
* property instance to be inserted
* @param propertyType
* property type of the property
* @param featureRow
* table row of the parent feature instance
* @throws TransactionException
*/
private void insertProperty( MappedFeatureType featureType, FeatureProperty property,
MappedPropertyType propertyType, InsertRow featureRow )
throws TransactionException {
if ( propertyType instanceof SimplePropertyType ) {
LOG.logDebug( "- Simple property '" + propertyType.getName() + "', value='"
+ getPropertyValue( property ) + "'." );
insertProperty( (MappedSimplePropertyType) propertyType, property, featureRow );
} else if ( propertyType instanceof GeometryPropertyType ) {
LOG.logDebug( "- Geometry property: '" + propertyType.getName() + "'" );
insertProperty( (MappedGeometryPropertyType) propertyType, property, featureRow );
} else if ( propertyType instanceof FeaturePropertyType ) {
LOG.logDebug( "- Feature property: '" + propertyType.getName() + "'" );
insertProperty( (MappedFeaturePropertyType) propertyType, property, featureRow,
featureType.getGMLSchema() );
} else {
throw new TransactionException( "Unhandled property type '"
+ propertyType.getClass().getName() + "'." );
}
}
/**
* Inserts the given simple property (stored in feature table or in related table).
*
* @param pt
* @param property
* @param featureRow
* @throws TransactionException
*/
private void insertProperty( MappedSimplePropertyType pt, FeatureProperty property,
InsertRow featureRow )
throws TransactionException {
SimpleContent content = pt.getContent();
if ( content.isUpdateable() ) {
if (content instanceof MappingField) {
MappingField mf = (MappingField) content;
String propertyColumn = mf.getField();
Object propertyValue = property.getValue();
int propertyType = mf.getType();
TableRelation[] relations = pt.getTableRelations();
insertProperty( propertyColumn, propertyValue, propertyType, relations, featureRow );
}
}
}
/**
* Inserts the given geometry property (stored in feature table or in related table).
*
* @param pt
* @param property
* @param featureRow
* @throws TransactionException
*/
private void insertProperty( MappedGeometryPropertyType pt, FeatureProperty property,
InsertRow featureRow )
throws TransactionException {
String propertyColumn = pt.getMappingField().getField();
Geometry deegreeGeometry = (Geometry) property.getValue();
Object dbGeometry;
try {
dbGeometry = this.datastore.convertDegreeToDBGeometry( deegreeGeometry );
} catch ( DatastoreException e ) {
throw new TransactionException( e.getMessage(), e );
}
int propertyType = pt.getMappingField().getType();
TableRelation[] relations = pt.getTableRelations();
insertProperty( propertyColumn, dbGeometry, propertyType, relations, featureRow );
}
/**
* Inserts the given simple / geometry property (stored in feature table or in related table).
*
* @param propertyColumn
* @param propertyValue
* @param propertyType
* @param featureRow
* @throws TransactionException
*/
private void insertProperty( String propertyColumn, Object propertyValue, int propertyType,
TableRelation[] relations, InsertRow featureRow )
throws TransactionException {
if ( relations == null || relations.length == 0 ) {
// property is stored in feature table
featureRow.setColumn( propertyColumn, propertyValue, propertyType, false );
} else {
// property is stored in related table
if ( relations.length > 1 ) {
throw new TransactionException( "properties in related tables are not allowed here" );
}
if ( !relations[0].isFromFK() ) {
// fk is in property table
MappingField[] pkFields = relations[0].getFromFields();
MappingField[] fkFields = relations[0].getToFields();
for ( int i = 0; i < pkFields.length; i++ ) {
InsertField pkField = featureRow.getColumn( pkFields[i].getField() );
if ( pkField == null ) {
String msg = "Missing foreign key " + pkFields[i].getField() + " / "
+ pkFields[i].getTable();
throw new TransactionException( msg );
}
int pkColumnType = pkField.getSQLType();
int fkColumnType = fkFields[i].getType();
if ( pkColumnType != fkColumnType ) {
String msg = "FK_PK_TYPE_MISMATCH";
throw new TransactionException( msg );
}
InsertRow insertRow = new InsertRow( relations[0].getToTable() );
insertRow.linkColumn( fkFields[i].getField(), pkField );
insertRow.setColumn( propertyColumn, propertyValue, propertyType, false );
this.insertRows.add( insertRow );
}
} else {
// fk is in feature table
MappingField[] pkFields = relations[0].getToFields();
MappingField[] fkFields = relations[0].getFromFields();
// generate necessary primary key value
InsertField pkField = null;
try {
Object pk = null;
// TODO remove hack!!!
if ( relations[0].getIdGenerator() instanceof ParentIDGenerator ) {
InsertField field = featureRow.getColumn( "ID" );
if ( field == null ) {
throw new TransactionException( "No value for ID available!" );
}
pk = field.getValue();
} else {
pk = relations[0].getNewPK( this.dsTa );
}
InsertRow insertRow = findOrCreateRow( relations[0].getToTable(),
pkFields[0].getField(), pk );
pkField = insertRow.setColumn( pkFields[0].getField(), pk,
pkFields[0].getType(), true );
insertRow.setColumn( propertyColumn, propertyValue, propertyType, false );
} catch ( IdGenerationException e ) {
throw new TransactionException( e.getMessage(), e );
}
featureRow.linkColumn( fkFields[0].getField(), pkField );
}
}
}
/**
* Inserts the given feature property.
*
* @param pt
* @param property
* @param featureRow
* @throws TransactionException
*/
private void insertProperty( MappedFeaturePropertyType pt, FeatureProperty property,
InsertRow featureRow, MappedGMLSchema schema )
throws TransactionException {
// find (concrete) subfeature type for the given property instance
MappedFeatureType propertyFeatureType = pt.getFeatureTypeReference().getFeatureType();
FeatureType[] substitutions = schema.getSubstitutions( propertyFeatureType );
Feature subFeature = (Feature) property.getValue();
MappedFeatureType subFeatureType = null;
for ( int i = 0; i < substitutions.length; i++ ) {
if ( substitutions[i].getName().equals( subFeature.getName() ) ) {
subFeatureType = (MappedFeatureType) substitutions[i];
break;
}
}
if ( subFeatureType == null ) {
String msg = "ERROR_FEATURE_NOT_SUBSTITUTABLE " + propertyFeatureType.getName() + "->"
+ subFeature.getName();
throw new TransactionException( msg );
}
boolean ftIsAbstract = propertyFeatureType.isAbstract();
TableRelation[] relations = pt.getTableRelations();
if ( relations == null || relations.length < 1 ) {
throw new TransactionException(
"Invalid feature property definition, feature property "
+ "mappings must use at least one 'TableRelation' element." );
}
// workaround for links to dummy InsertRows (of already stored features)
boolean cutLink = subFeature.getId().startsWith( FeatureIdAssigner.EXIST_PREFIX );
InsertRow subFeatureRow = null;
if ( cutLink ) {
try {
Object fidValue = FeatureId.removeFIDPrefix( subFeature.getId().substring( 1 ),
subFeatureType.getGMLId() );
subFeatureRow = new FeatureRow( subFeatureType.getTable() );
// add column value for fid (primary key)
String fidColumn = subFeatureType.getGMLId().getIdFields()[0].getField();
subFeatureRow.setColumn( fidColumn, fidValue,
subFeatureType.getGMLId().getIdFields()[0].getType(), true );
} catch ( DatastoreException e ) {
throw new TransactionException( e );
}
} else {
// insert sub feature (if it is not already stored)
subFeatureRow = insertFeature( subFeature );
}
if ( relations.length == 1 ) {
if ( relations[0].isFromFK() ) {
// fk is in feature table
MappingField[] pkFields = relations[0].getToFields();
MappingField[] fkFields = relations[0].getFromFields();
for ( int i = 0; i < pkFields.length; i++ ) {
InsertField pkField = subFeatureRow.getColumn( pkFields[i].getField() );
if ( pkField == null ) {
String msg = "Missing foreign key " + pkField.getColumnName() + " / "
+ pkField.getTable();
throw new TransactionException( msg );
}
int pkColumnType = pkField.getSQLType();
int fkColumnType = fkFields[i].getType();
if ( pkColumnType != fkColumnType ) {
String msg = "ERROR_FK_PK_TYPE_MISMATCH";
throw new TransactionException( msg );
}
if ( !cutLink ) {
featureRow.linkColumn( fkFields[i].getField(), pkField );
} else {
featureRow.setColumn( fkFields[i].getField(), pkField.getValue(),
pkField.getSQLType(), false );
}
}
if ( ftIsAbstract ) {
String typeField = FT_PREFIX + relations[0].getToTable();
featureRow.setColumn( typeField, subFeatureType.getName().getLocalName(),
Types.VARCHAR, false );
}
} else {
// fk is in subfeature table
MappingField[] pkFields = relations[0].getFromFields();
MappingField[] fkFields = relations[0].getToFields();
InsertField pkField = featureRow.getColumn( pkFields[0].getField() );
if ( pkField == null ) {
String msg = "Missing foreign key " + pkField.getColumnName() + " / "
+ pkField.getTable();
throw new TransactionException( msg );
}
int pkColumnType = pkField.getSQLType();
int fkColumnType = fkFields[0].getType();
if ( pkColumnType != fkColumnType ) {
String msg = "ERROR_FK_PK_TYPE_MISMATCH";
throw new TransactionException( msg );
}
if ( !cutLink ) {
subFeatureRow.linkColumn( fkFields[0].getField(), pkField );
} else {
featureRow.setColumn( fkFields[0].getField(), pkField.getValue(),
pkField.getSQLType(), false );
}
}
} else if ( relations.length == 2 ) {
// insert into join table
String joinTable = relations[0].getToTable();
MappingField[] leftKeyFields = relations[0].getToFields();
MappingField[] rightKeyFields = relations[1].getFromFields();
InsertRow jtRow = new InsertRow( joinTable );
if ( ftIsAbstract ) {
jtRow.setColumn( FT_COLUMN, subFeatureType.getName().getLocalName(), Types.VARCHAR,
false );
}
if ( !relations[0].isFromFK() ) {
// left key field in join table is fk
MappingField[] pkFields = relations[0].getFromFields();
InsertField pkField = featureRow.getColumn( pkFields[0].getField() );
if ( pkField == null ) {
throw new TransactionException(
"Insertion of feature property using join table failed: "
+ "no value for join table key column '"
+ pkField.getColumnName()
+ "'." );
}
jtRow.linkColumn( leftKeyFields[0].getField(), pkField );
} else {
// left key field in join table is pk
MappingField[] pkFields = relations[0].getToFields();
// generate necessary primary key value
InsertField pkField = null;
try {
Object pk = relations[0].getNewPK( this.dsTa );
pkField = jtRow.setColumn( pkFields[0].getField(), pk, pkFields[0].getType(),
true );
} catch ( IdGenerationException e ) {
throw new TransactionException( e.getMessage(), e );
}
featureRow.linkColumn( relations[0].getFromFields()[0].getField(), pkField );
}
if ( relations[1].isFromFK() ) {
// right key field in join table is fk
MappingField[] pkFields = relations[1].getToFields();
InsertField pkField = subFeatureRow.getColumn( pkFields[0].getField() );
if ( pkField == null ) {
throw new TransactionException(
"Insertion of feature property using join table failed: "
+ "no value for join table key column '"
+ pkField.getColumnName()
+ "'." );
}
if ( !cutLink ) {
jtRow.linkColumn( rightKeyFields[0].getField(), pkField );
} else {
jtRow.setColumn( rightKeyFields[0].getField(), pkField.getValue(),
pkField.getSQLType(), false );
}
} else {
// right key field in join table is pk
MappingField[] pkFields = relations[1].getFromFields();
// generate necessary primary key value
InsertField pkField = null;
try {
Object pk = relations[1].getNewPK( this.dsTa );
pkField = jtRow.setColumn( pkFields[0].getField(), pk, pkFields[0].getType(),
true );
} catch ( IdGenerationException e ) {
throw new TransactionException( e.getMessage(), e );
}
if ( !cutLink ) {
subFeatureRow.linkColumn( relations[1].getToFields()[0].getField(), pkField );
}
}
this.insertRows.add( jtRow );
} else {
throw new TransactionException(
"Insertion of feature properties stored in related tables "
+ "connected via more than one join table is not supported." );
}
}
/**
* Checks whether the feature that corresponds to the given FeatureRow is already stored in the
* database.
*
* @param featureRow
* @return
* @throws DatastoreException
*/
private boolean doesFeatureExist( FeatureRow featureRow )
throws TransactionException {
boolean exists = false;
InsertField pkField = featureRow.getPKColumn();
SeQuery stmt = null;
try {
stmt = buildFeatureSelect( pkField.getColumnName(), pkField.getValue(),
featureRow.getTable() );
stmt.execute();
SeRow row = stmt.fetch();
if ( null != row ) {
exists = true;
}
row = stmt.fetch();
if ( null != row ) {
String msg = "ERROR_FEATURE_QUERY_MORE_THAN_ONE_RESULT";
LOG.logError( msg );
throw new TransactionException( msg );
}
} catch ( Exception e ) {
throw new TransactionException( e );
} finally {
try {
stmt.close();
} catch ( Exception e ) {
LOG.logDebug( "Error in SDE command", e );
}
}
return exists;
}
/**
* Builds a SELECT statement that checks for the existence of a feature with the given id.
*
* @param fidColumn
* @param typeCode
* @param fidValue
* @param table
* @return the statement
*/
private SeQuery buildFeatureSelect( String fidColumn, Object fidValue, String table ) {
SeQuery query = null;
try {
SeSqlConstruct constr = new SeSqlConstruct( table, fidColumn + "='"
+ fidValue.toString() + "'" );
String[] columns = new String[1];
columns[0] = fidColumn;
query = new SeQuery( getConnection().getConnection(), columns, constr );
query.setState( getConnection().getState().getId(),
new SeObjectId( SeState.SE_NULL_STATE_ID ),
SeState.SE_STATE_DIFF_NOCHECK );
query.prepareQuery();
} catch ( Exception e ) {
LOG.logError( "Error building featureSelect", e );
}
return query;
}
private InsertRow findOrCreateRow( String table, String pkColumn, Object value ) {
Iterator<InsertRow> rowIter = this.insertRows.iterator();
boolean found = false;
InsertRow row = null;
while ( rowIter.hasNext() ) {
row = rowIter.next();
if ( row.getTable().equals( table ) ) {
InsertField field = row.getColumn( pkColumn );
if ( value.equals( field.getValue() ) ) {
found = true;
LOG.logDebug( "Found matching row " + row );
break;
}
}
}
if ( !found ) {
row = new InsertRow( table );
this.insertRows.add( row );
}
return row;
}
private String getPropertyValue( FeatureProperty property ) {
Object value = property.getValue();
StringBuffer sb = new StringBuffer();
if ( value instanceof Object[] ) {
Object[] objects = (Object[]) value;
for ( int i = 0; i < objects.length; i++ ) {
sb.append( objects[i] );
}
} else {
sb.append( value );
}
return sb.toString();
}
/**
* Transforms the given <code>List</code> of <code>InsertRows</code> into SQL INSERT
* statements and executes them using the underlying JDBC connection.
*
* @param inserts
* @throws TransactionException
* if an SQL error occurs
*/
private void executeInserts( List<InsertRow> inserts )
throws TransactionException {
SeInsert stmt = null;
for ( InsertRow row : inserts ) {
if ( row instanceof FeatureRow ) {
if ( doesFeatureExist( (FeatureRow) row ) ) {
LOG.logDebug( "Skipping feature row. Already present in db." );
continue;
}
}
try {
stmt = createStatement( row );
stmt.execute();
} catch ( Exception e ) {
String msg = "Error performing insert: " + e.getMessage();
LOG.logError( msg, e );
throw new TransactionException( msg, e );
} finally {
if ( stmt != null ) {
try {
stmt.close();
} catch ( Exception e ) {
String msg = "Error closing statement: " + e.getMessage();
LOG.logError( msg, e );
}
}
}
}
}
private SeInsert createStatement( InsertRow row )
throws SeException {
SeInsert inserter = new SeInsert( conn.getConnection() );
inserter.setState( conn.getState().getId(), new SeObjectId( SeState.SE_NULL_STATE_ID ),
SeState.SE_STATE_DIFF_NOCHECK );
Collection fields = row.getColumns();
String[] columns = new String[fields.size()];
int i = 0;
for ( Iterator<InsertField> iter = fields.iterator(); iter.hasNext(); i++ ) {
InsertField field = iter.next();
columns[i] = field.getColumnName();
}
inserter.intoTable( row.getTable(), columns );
SeRow insertRow = inserter.getRowToSet();
for ( i = 0; i < columns.length; i++ ) {
InsertField field = row.getColumn( columns[i] );
SDEAdapter.setRowValue( insertRow, i, field.getValue(),
SDEAdapter.mapSQL2SDE( field.getSQLType() ) );
}
return inserter;
}
/**
* Merges the given <code>InsertRow</code>s by eliminating rows that have identical content
* (except for their primary keys).
* <p>
* This only applies to non-FeatureRows: there are never two FeatureRows that may be treated as
* identical, because unique feature ids have been assigned to them before.
*
* @see FeatureIdAssigner
*
* @param insertRows
* @return
*/
private List<InsertRow> mergeInsertRows( List<InsertRow> insertRows ) {
List<InsertRow> result = new ArrayList<InsertRow>();
// keys: table names, values: inserts into the table
Map<String, Collection<InsertRow>> tableMap = new HashMap<String, Collection<InsertRow>>();
// build table lookup map
Iterator<InsertRow> iter = insertRows.iterator();
while ( iter.hasNext() ) {
InsertRow insertRow = iter.next();
Collection<InsertRow> tableInserts = tableMap.get( insertRow.getTable() );
if ( tableInserts == null ) {
tableInserts = new ArrayList<InsertRow>();
tableMap.put( insertRow.getTable(), tableInserts );
}
tableInserts.add( insertRow );
}
iter = insertRows.iterator();
while ( iter.hasNext() ) {
InsertRow insertRow = iter.next();
boolean insert = true;
if ( !( insertRow instanceof FeatureRow ) ) {
Collection<InsertRow> tableInserts = tableMap.get( insertRow.getTable() );
Iterator<InsertRow> candidatesIter = tableInserts.iterator();
while ( candidatesIter.hasNext() ) {
InsertRow candidate = candidatesIter.next();
if ( insertRow != candidate ) {
if ( compareInsertRows( insertRow, candidate ) ) {
LOG.logDebug( "Removing InsertRow: " + insertRow.hashCode() + " "
+ insertRow + " - duplicate of: " + candidate );
replaceInsertRow( insertRow, candidate );
insert = false;
tableInserts.remove( insertRow );
break;
}
}
}
}
if ( insert ) {
result.add( insertRow );
}
}
return result;
}
private boolean compareInsertRows( InsertRow row1, InsertRow row2 ) {
Collection<InsertField> fields1 = row1.getColumns();
Iterator<InsertField> iter = fields1.iterator();
while ( iter.hasNext() ) {
InsertField field1 = iter.next();
if ( !field1.isPK() ) {
InsertField field2 = row2.getColumn( field1.getColumnName() );
Object value1 = field1.getValue();
Object value2 = null;
if ( field2 != null )
value2 = field2.getValue();
if ( value1 == null ) {
if ( value2 == null ) {
continue;
}
return false;
}
if ( !value1.equals( value2 ) ) {
return false;
}
}
}
return true;
}
private void replaceInsertRow( InsertRow oldRow, InsertRow newRow ) {
Collection<InsertField> oldFields = oldRow.getColumns();
for ( InsertField field : oldFields ) {
InsertField toField = field.getReferencedField();
if ( toField != null ) {
LOG.logDebug( "Removing reference to field '" + toField + "'" );
toField.removeReferencingField( field );
}
}
Collection<InsertField> referencingFields = oldRow.getReferencingFields();
for ( InsertField fromField : referencingFields ) {
LOG.logDebug( "Replacing reference for field '" + fromField + "'" );
InsertField field = newRow.getColumn( fromField.getReferencedField().getColumnName() );
LOG.logDebug( "" + field );
fromField.relinkField( field );
}
}
}
/***************************************************************************************************
* Changes to this class. What the people have been up to:
* $Log: SDEInsertHandler.java,v $
* Revision 1.8 2006/09/26 16:44:51 mschneider
* Refactored because of moving of TransactionException.
*
* Revision 1.7 2006/08/29 15:53:57 mschneider
* Changed SimpleContent#isVirtual() to SimpleContent#isUpdateable().
*
* Revision 1.6 2006/08/23 16:34:06 mschneider
* Added handling of virtual properties. Needs testing.
*
* Revision 1.5 2006/08/22 18:14:42 mschneider
* Refactored due to cleanup of org.deegree.io.datastore.schema package.
*
* Revision 1.4 2006/08/21 16:42:36 mschneider
* Refactored due to cleanup (and splitting) of org.deegree.io.datastore.schema package.
*
* Revision 1.3 2006/08/21 15:44:38 mschneider
* Refactored due to cleanup (and splitting) of org.deegree.io.datastore.schema package.
*
* Revision 1.2 2006/08/06 20:38:51 poth
* never thrown exceptions and never read variables removed
*
* Revision 1.1 2006/05/21 19:06:21 poth
* initial load up
*
* Revision 1.1 2006/05/14 07:34:07 polli
* update and delete handler impledmented
*
* Revision 1.1 2006/05/09 14:51:52 polli
* no message
*
**************************************************************************************************/