package org.geotools.arcsde.session;
import static org.geotools.arcsde.session.Session.LOGGER;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import org.geotools.arcsde.ArcSdeException;
import com.esri.sde.sdk.client.SeColumnDefinition;
import com.esri.sde.sdk.client.SeConnection;
import com.esri.sde.sdk.client.SeDBMSInfo;
import com.esri.sde.sdk.client.SeDelete;
import com.esri.sde.sdk.client.SeError;
import com.esri.sde.sdk.client.SeException;
import com.esri.sde.sdk.client.SeInsert;
import com.esri.sde.sdk.client.SeLayer;
import com.esri.sde.sdk.client.SeObjectId;
import com.esri.sde.sdk.client.SeQuery;
import com.esri.sde.sdk.client.SeRasterColumn;
import com.esri.sde.sdk.client.SeRegistration;
import com.esri.sde.sdk.client.SeRelease;
import com.esri.sde.sdk.client.SeSqlConstruct;
import com.esri.sde.sdk.client.SeState;
import com.esri.sde.sdk.client.SeStreamOp;
import com.esri.sde.sdk.client.SeTable;
import com.esri.sde.sdk.client.SeUpdate;
import com.esri.sde.sdk.client.SeVersion;
public class Commands {
/**
* Creates either a direct child state of parentStateId, or a sibling being an exact copy of
* parentStatId if either the state can't be closed because its in use or parentStateId does not
* belong to the current user.
*/
public static final class CreateVersionStateCommand extends Command<SeState> {
private final long parentStateId;
public CreateVersionStateCommand(final long parentStateId) {
this.parentStateId = parentStateId;
}
@Override
public SeState execute(ISession session, SeConnection connection) throws SeException,
IOException {
SeState parentState = new SeState(connection, new SeObjectId(parentStateId));
SeState realParent = null;
boolean mergeParentToRealParent = false;
if (parentState.isOpen()) {
// only closed states can have child states
try {
parentState.close();
realParent = parentState;
} catch (SeException e) {
final int errorCode = e.getSeError().getSdeError();
if (SeError.SE_STATE_INUSE == errorCode
|| SeError.SE_NO_PERMISSIONS == errorCode) {
// it's not our state or somebody's editing it so we
// need to clone the parent,
// starting from the parent of the parent
realParent = new SeState(connection, parentState.getParentId());
mergeParentToRealParent = true;
} else {
throw e;
}
}
} else {
realParent = parentState;
}
// create the new state
SeState newState = new SeState(connection);
newState.create(realParent.getId());
if (mergeParentToRealParent) {
// a sibling of parentStateId was created instead of a
// child, we need to merge the changes
// in parentStateId to the new state so they refer to the
// same content.
// SE_state_merge applies changes to a parent state to
// create a new merged state.
// The new state is the child of the parent state with the
// changes of the second state.
// Both input states must have the same parent state.
// When a row has been changed in both parent and second
// states, the row from the changes state is used.
// The parent and changes states must be open or owned by
// the current user unless the current user is the ArcSDE
// DBA.
newState.merge(realParent.getId(), parentState.getId());
}
return newState;
}
}
/**
* Command to create, prepare, and execute a query.
*/
public static final class CreateAndExecuteQueryCommand extends Command<SeQuery> {
private final String[] propertyNames;
private final SeSqlConstruct sql;
public CreateAndExecuteQueryCommand(final String[] propertyNames, final SeSqlConstruct sql) {
this.propertyNames = propertyNames;
this.sql = sql;
}
@Override
public SeQuery execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
SeQuery query = new SeQuery(connection, propertyNames, sql);
query.prepareQuery();
query.execute();
return query;
}
}
public static final class CreateSeStateCommand extends Command<SeState> {
private final SeObjectId stateId;
public CreateSeStateCommand(final SeObjectId stateId) {
this.stateId = stateId;
}
@Override
public SeState execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
return new SeState(connection, stateId);
}
}
/**
* A command to close an {@link SeStreamOp stream} (ie, {@link SeDelete}, {@link SeInsert},
* {@link SeQuery}, {@link SeUpdate}).
*/
public static final class CloseStreamCommand extends Command<Object> {
private final SeStreamOp stream;
public CloseStreamCommand(final SeStreamOp stream) {
this.stream = stream;
}
@Override
public Void execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
stream.close();
return null;
}
}
public static final class CloseStateCommand extends Command<Object> {
private final SeState state;
public CloseStateCommand(final SeState state) {
this.state = state;
}
@Override
public Void execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
state.close();
return null;
}
}
public static final class DescribeTableCommand extends Command<SeColumnDefinition[]> {
private final SeTable table;
public DescribeTableCommand(SeTable table) {
this.table = table;
}
@Override
public SeColumnDefinition[] execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
return table.describe();
}
}
public static class CreateSeTableCommand extends Command<SeTable> {
private final String qualifiedName;
public CreateSeTableCommand(final String qualifiedName) {
this.qualifiedName = qualifiedName;
}
@Override
public SeTable execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
return new SeTable(connection, qualifiedName);
}
}
/**
* Command to check a connection is alive
*/
public static final Command<Void> TEST_SERVER_COMMAND = new Command<Void>() {
@Override
public Void execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
connection.testServer(Session.TEST_SERVER_ROUNDTRIP_INTERVAL_SECONDS);
return null;
}
};
/**
* Command to fetch the default version
*/
public static final Command<SeVersion> GetDefaultVersionCommand = new GetVersionCommand(
SeVersion.SE_QUALIFIED_DEFAULT_VERSION_NAME);
/**
* Command to fetch a version.
*
* @author Gabriel Roldan
*/
public static final class GetVersionCommand extends Command<SeVersion> {
private String versionName;
public GetVersionCommand(final String versionName) {
this.versionName = versionName;
}
@Override
public SeVersion execute(ISession session, SeConnection connection) throws SeException,
IOException {
final SeVersion version;
try {
version = new SeVersion(connection, versionName);
} catch (SeException cause) {
if (cause.getSeError().getSdeError() == -126) {
ArrayList<String> available = new ArrayList<String>();
try {
SeVersion[] versionList = connection.getVersionList(null);
for (SeVersion v : versionList) {
available.add(v.getName());
}
throw new ArcSdeException("Specified ArcSDE version does not exist: "
+ versionName + ". Available versions are: " + available, cause);
} catch (SeException ignorable) {
// hum... ignore
throw new ArcSdeException("Specified ArcSDE version does not exist: "
+ versionName, cause);
}
} else {
throw cause;
}
}
version.getInfo();
return version;
}
}
public static final Command<Void> StartTransactionCommand = new Command<Void>() {
@Override
public Void execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
connection.setTransactionAutoCommit(0);
connection.startTransaction();
return null;
}
};
public static final Command<List<String>> GetRasterColumnNamesCommand = new Command<List<String>>() {
@SuppressWarnings("unchecked")
@Override
public List<String> execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
final Vector<SeRasterColumn> rasterColumns = connection.getRasterColumns();
List<String> names = new ArrayList<String>(rasterColumns.size());
for (SeRasterColumn col : rasterColumns) {
names.add(col.getQualifiedTableName());
}
return names;
}
};
public static final Command<Void> CommitTransactionCommand = new Command<Void>() {
@Override
public Void execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
connection.commitTransaction();
return null;
}
};
public static final Command<Void> RollbackTransactionCommand = new Command<Void>() {
@Override
public Void execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
connection.rollbackTransaction();
return null;
}
};
public static final Command<Void> CloseConnectionCommand = new Command<Void>() {
@Override
public Void execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
connection.close();
LOGGER.fine(session.toString() + " successfully closed");
return null;
}
};
public static final Command<List<SeLayer>> GetLayersCommand = new Command<List<SeLayer>>() {
@SuppressWarnings("unchecked")
@Override
public List<SeLayer> execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
return connection.getLayers();
}
};
public static final Command<String> GetUserCommand = new Command<String>() {
@Override
public String execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
return connection.getUser();
}
};
public static final Command<SeRelease> GetReleaseCommand = new Command<SeRelease>() {
@Override
public SeRelease execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
return connection.getRelease();
}
};
public static final Command<String> GetDatabaseNameCommand = new Command<String>() {
@Override
public String execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
return connection.getDatabaseName();
}
};
public static final Command<SeDBMSInfo> getDBMSInfoCommand = new Command<SeDBMSInfo>() {
@Override
public SeDBMSInfo execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
return connection.getDBMSInfo();
}
};
public static final Command<SeInsert> CreateSeInsertCommand = new Command<SeInsert>() {
@Override
public SeInsert execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
return new SeInsert(connection);
}
};
public static final Command<SeUpdate> CreateSeUpdateCommand = new Command<SeUpdate>() {
@Override
public SeUpdate execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
return new SeUpdate(connection);
}
};
public static final Command<SeDelete> CreateSeDeleteCommand = new Command<SeDelete>() {
@Override
public SeDelete execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
return new SeDelete(connection);
}
};
public static final class CreateSeRegistrationCommand extends Command<SeRegistration> {
private String typeName;
public CreateSeRegistrationCommand(final String typeName) {
this.typeName = typeName;
}
@Override
public SeRegistration execute(final ISession session, final SeConnection connection)
throws SeException, IOException {
return new SeRegistration(connection, typeName);
}
}
}