/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*
* 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;
* version 2.1 of the License.
*
* 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.
*
*/
package org.geotools.arcsde.data;
import static org.geotools.arcsde.session.ArcSDEConnectionConfig.CONNECTION_TIMEOUT_PARAM_NAME;
import static org.geotools.arcsde.session.ArcSDEConnectionConfig.INSTANCE_NAME_PARAM_NAME;
import static org.geotools.arcsde.session.ArcSDEConnectionConfig.MAX_CONNECTIONS_PARAM_NAME;
import static org.geotools.arcsde.session.ArcSDEConnectionConfig.MIN_CONNECTIONS_PARAM_NAME;
import static org.geotools.arcsde.session.ArcSDEConnectionConfig.PASSWORD_PARAM_NAME;
import static org.geotools.arcsde.session.ArcSDEConnectionConfig.PORT_NUMBER_PARAM_NAME;
import static org.geotools.arcsde.session.ArcSDEConnectionConfig.SERVER_NAME_PARAM_NAME;
import static org.geotools.arcsde.session.ArcSDEConnectionConfig.USER_NAME_PARAM_NAME;
import java.io.Serializable;
import java.util.Map;
import java.util.logging.Logger;
import org.geotools.arcsde.session.ArcSDEConnectionConfig;
/**
* Represents a set of ArcSDE database connection parameters. Instances of this class are used to
* validate ArcSDE connection params as in <code>DataSourceFactory.canProcess(java.util.Map)</code>
* and serves as keys for maintaining single <code>SdeConnectionPool</code>'s by each set of
* connection properties
*
* @author Gabriel Roldan
*
* @source $URL$
* datastore/src/main/java /org/geotools/arcsde/pool/ArcSDEConnectionConfig.java $
* @version $Id$
*/
public class ArcSDEDataStoreConfig {
/*
* ArcSDEDataStoreConfige's logger
*/
private static final Logger LOGGER = org.geotools.util.logging.Logging
.getLogger("org.geotools.arcsde.pool");
/**
* message of the exception thrown if a mandatory parameter is not supplied
*/
private static final String NULL_ARGUMENTS_MSG = "Illegal arguments. At least one of them was null. Check to pass "
+ "correct values to dbtype, server, port, database, user and password parameters";
private static final String ILLEGAL_ARGUMENT_MSG = " is not valid for parameter ";
/** must equals to <code>"arcsde"</code> */
public static final String DBTYPE_PARAM_NAME = "dbtype";
/** constant to pass "arcsde" as DBTYPE_PARAM */
public static final String DBTYPE_PARAM_VALUE = "arcsde";
/** namespace URI assigned to datastore instance */
public static final String NAMESPACE_PARAM_NAME = "namespace";
public static final String VERSION_PARAM_NAME = "database.version";
public static final String ALLOW_NON_SPATIAL_TABLES_PARAM_NAME = "datastore.allowNonSpatialTables";
/** default number of connections a pool creates at first population */
public static final int DEFAULT_CONNECTIONS = 2;
/** default number of maximum allowable connections a pool can hold */
public static final int DEFAULT_MAX_CONNECTIONS = 6;
public static final int DEFAULT_MAX_WAIT_TIME = 500;
/** namespace URI assigned to datastore */
private String namespaceUri;
/** ArcSDE database version name, or null for DEFAULT version */
private String version;
/** whether to publish arcsde registered, non-spatial tables */
private boolean allowNonSpatialTables;
private ArcSDEConnectionConfig sessionConfig = new ArcSDEConnectionConfig();
public ArcSDEConnectionConfig getSessionConfig() {
return sessionConfig;
}
/**
* Configure arcsde connection information from supplied connection parameters.
*
* @param params
* Connection parameters
* @throws NullPointerException
* if at least one mandatory parameter is null
* @throws IllegalArgumentException
* if at least one mandatory parameter is present but does not have a "valid" value.
*/
public ArcSDEDataStoreConfig(Map<String, Serializable> params) throws IllegalArgumentException {
init(params);
}
public ArcSDEDataStoreConfig(ArcSDEConnectionConfig sessionConfig, final String namespace,
final String versionName, final boolean allowNonSpatialTables) {
this.sessionConfig = sessionConfig;
this.namespaceUri = namespace;
this.allowNonSpatialTables = allowNonSpatialTables;
this.version = versionName;
}
/**
* Extra connection parameters from the provided map.
*
* @param params
* Connection parameters
* @throws NumberFormatException
* If port could not be parsed into a number
* @throws IllegalArgumentException
* If any of the parameters are invalid
*/
private void init(Map<String, Serializable> params) throws NumberFormatException,
IllegalArgumentException {
String dbtype = (String) params.get(DBTYPE_PARAM_NAME);
String server = (String) params.get(SERVER_NAME_PARAM_NAME);
String port = String.valueOf(params.get(PORT_NUMBER_PARAM_NAME));
String instance = (String) params.get(INSTANCE_NAME_PARAM_NAME);
String user = (String) params.get(USER_NAME_PARAM_NAME);
String pwd = (String) params.get(PASSWORD_PARAM_NAME);
/** ESRI Direct Connect needs port parameter as String */
String _port = checkParams(dbtype, server, port, instance, user, pwd);
sessionConfig.setServerName(server);
sessionConfig.setPortNumber(_port);
sessionConfig.setDatabaseName(instance);
sessionConfig.setUserName(user);
sessionConfig.setPassword(pwd);
setUpOptionalParams(params);
}
public Map<String, Serializable> toMap() {
Map<String, Serializable> params = sessionConfig.toMap();
params.put(DBTYPE_PARAM_NAME, DBTYPE_PARAM_VALUE);
params.put(VERSION_PARAM_NAME, getVersion());
params.put(NAMESPACE_PARAM_NAME, getNamespaceUri());
params.put(ALLOW_NON_SPATIAL_TABLES_PARAM_NAME, isAllowNonSpatialTables());
return params;
}
/**
* Handle optional parameters; most are focused on connection pool use.
*
* @param params
* Connection parameters
* @throws IllegalArgumentException
* If any of the optional prameters are invlaid.
*/
private void setUpOptionalParams(Map<String, Serializable> params)
throws IllegalArgumentException {
String exceptionMsg = "";
Object ns = params.get(NAMESPACE_PARAM_NAME);
this.namespaceUri = ns == null ? null : String.valueOf(ns);
Integer minConnections = getInt(params.get(MIN_CONNECTIONS_PARAM_NAME), DEFAULT_CONNECTIONS);
Integer maxConnections = getInt(params.get(MAX_CONNECTIONS_PARAM_NAME),
DEFAULT_MAX_CONNECTIONS);
Integer connTimeOut = getInt(params.get(CONNECTION_TIMEOUT_PARAM_NAME),
DEFAULT_MAX_WAIT_TIME);
this.version = (String) params.get(VERSION_PARAM_NAME);
Object nonSpatial = params.get(ALLOW_NON_SPATIAL_TABLES_PARAM_NAME);
this.allowNonSpatialTables = nonSpatial == null ? false : Boolean.valueOf(String
.valueOf(nonSpatial));
if (minConnections.intValue() <= 0) {
exceptionMsg += MIN_CONNECTIONS_PARAM_NAME + " must be a positive integer. ";
}
if (maxConnections.intValue() <= 0) {
exceptionMsg += MAX_CONNECTIONS_PARAM_NAME + " must be a positive integer. ";
}
if (connTimeOut.intValue() <= 0) {
exceptionMsg += CONNECTION_TIMEOUT_PARAM_NAME + " must be a positive integer. ";
}
if (minConnections.intValue() > maxConnections.intValue()) {
exceptionMsg += MIN_CONNECTIONS_PARAM_NAME + " must be lower than "
+ MAX_CONNECTIONS_PARAM_NAME + ".";
}
if (exceptionMsg.length() != 0) {
throw new IllegalArgumentException(exceptionMsg);
}
sessionConfig.setMinConnections(minConnections);
sessionConfig.setMaxConnections(maxConnections);
sessionConfig.setConnTimeOut(connTimeOut);
}
/**
* Convert value to an Integer, or use the default value
*
* @param value
* Object to convert to int
* @param defaultValue
* Default value if conversion fails
* @return value as an interger, or default value if that is not possible
*/
private static final Integer getInt(Object value, int defaultValue) {
if (value == null) {
return Integer.valueOf(defaultValue);
}
String sVal = String.valueOf(value);
try {
return Integer.valueOf(sVal);
} catch (NumberFormatException ex) {
return Integer.valueOf(defaultValue);
}
}
private static String checkParams(String dbType, String serverName, String portNumber,
String databaseName, String userName, String userPassword)
throws IllegalArgumentException, NullPointerException {
// check if dbtype is 'arcsde'
if (!(DBTYPE_PARAM_VALUE.equals(dbType))) {
throw new IllegalArgumentException("parameter dbtype must be " + DBTYPE_PARAM_VALUE);
}
// check for nullity
if ((serverName == null) || (portNumber == null) || (userName == null)
|| (userPassword == null)) {
throw new NullPointerException(NULL_ARGUMENTS_MSG);
}
if (serverName.length() == 0) {
throwIllegal(SERVER_NAME_PARAM_NAME, serverName);
}
if (databaseName == null || databaseName.length() == 0) {
LOGGER.fine("No database name specified");
}
if (userName.length() == 0) {
throwIllegal(USER_NAME_PARAM_NAME, userName);
}
if (userPassword.length() == 0) {
throwIllegal(PASSWORD_PARAM_NAME, userPassword);
}
String port = null;
try {
/**
* in DirectConnect Mode for Oracle, the port has following syntax: sde:oracle10g or
* sde:oracle10g:/:<schema> so check portNumber for colon character
*/
if (portNumber.indexOf(":") > 0) {
port = portNumber;
} else {
port = Integer.valueOf(portNumber).toString();
}
} catch (NumberFormatException ex) {
throwIllegal(PORT_NUMBER_PARAM_NAME, portNumber);
}
return port;
}
private static void throwIllegal(String paramName, String paramValue)
throws IllegalArgumentException {
throw new IllegalArgumentException("'" + paramValue + "'" + ILLEGAL_ARGUMENT_MSG
+ paramName);
}
public String getNamespaceUri() {
return namespaceUri;
}
public String getDatabaseName() {
return sessionConfig.getDatabaseName();
}
/** ESRI Direct Connect needs port parameter as String */
public String getPortNumber() {
return sessionConfig.getPortNumber();
}
public String getServerName() {
return sessionConfig.getServerName();
}
public String getUserName() {
return sessionConfig.getUserName();
}
public String getUserPassword() {
return sessionConfig.getPassword();
}
@Override
public int hashCode() {
int hash = 37;
hash *= getServerName().hashCode();
hash *= getPortNumber().hashCode();
hash *= getUserName().hashCode();
return hash;
}
/**
* Checks for equality over another <code>ArcSDEConnectionConfig</code>, taking into account the
* values of database name, user name, and port number.
*/
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof ArcSDEDataStoreConfig)) {
return false;
}
ArcSDEDataStoreConfig config = (ArcSDEDataStoreConfig) o;
return config.getServerName().equals(getServerName())
&& config.getPortNumber().equals(getPortNumber())
&& config.getUserName().equals(getUserName());
}
public Integer getConnTimeOut() {
return sessionConfig.getConnTimeOut();
}
public Integer getMaxConnections() {
return sessionConfig.getMaxConnections();
}
public Integer getMinConnections() {
return sessionConfig.getMinConnections();
}
/**
* @return the ArcSDE version name to connect to
*/
public String getVersion() {
return version;
}
/**
* @return whether to publish ArcSDE registered, non-spatial tables
*/
public boolean isAllowNonSpatialTables() {
return allowNonSpatialTables;
}
/**
* @return a human friendly description of this parameter holder contents (password is masked),
* mostly usefull for stack traces
*/
@Override
public String toString() {
StringBuffer sb = new StringBuffer(getClass().getName() + "[");
sb.append("dbtype=").append(ArcSDEDataStoreConfig.DBTYPE_PARAM_VALUE);
sb.append(", server=").append(getServerName());
sb.append(", port=").append(getPortNumber());
sb.append(", instance=").append(getDatabaseName());
sb.append(", user=").append(getUserName());
// hidding password as the result of this method
// is probably going to end up in a stack trace
sb.append(", password=*****");
sb.append(", version='").append(version == null ? "[DEFAULT]" : version).append("'");
sb.append(", non-spatial:").append(allowNonSpatialTables);
sb.append(", minConnections=").append(getMinConnections());
sb.append(", maxConnections=").append(getMaxConnections());
sb.append(", connTimeOut=").append(getConnTimeOut());
sb.append("]");
return sb.toString();
}
}