package com.revolsys.gis.postgresql;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.sql.DataSource;
import org.postgresql.Driver;
import com.revolsys.collection.map.Maps;
import com.revolsys.jdbc.io.JdbcDatabaseFactory;
import com.revolsys.jdbc.io.JdbcRecordStore;
import com.revolsys.record.schema.FieldDefinition;
import com.revolsys.record.schema.RecordStore;
import com.revolsys.util.Property;
import com.revolsys.util.Strings;
import com.revolsys.util.UrlUtil;
public class PostgreSQL implements JdbcDatabaseFactory {
private static final String REGEX_NAME = "\\p{IsAlphabetic}[\\p{IsAlphabetic}0-9_\\$]*";
private static final Pattern PATTERN_URL = Pattern.compile("jdbc:postgresql:(?:" // Prefix
+ "(?://" // Optional Start Host and port
+ "([a-zA-Z-0-9][a-zA-Z-0-9\\.\\-]*)" // Host
+ "(?::(\\d+))?" // Optional port
+ "/)?" // separator
+ "(" + REGEX_NAME + ")" // Database Name
+ ")?(?:\\?(" + REGEX_NAME + "=.*(?:&" + REGEX_NAME + "=.*)*))?" // Parameters
);
private static final List<FieldDefinition> CONNECTION_FIELD_DEFINITIONS = Arrays.asList();
@Override
public List<FieldDefinition> getConnectionFieldDefinitions() {
return CONNECTION_FIELD_DEFINITIONS;
}
@Override
public String getDriverClassName() {
return Driver.class.getName();
}
@Override
public String getName() {
return "PostgreSQL/PostGIS Database";
}
@Override
public String getProductName() {
return "PostgreSQL";
}
@Override
public List<String> getRecordStoreFileExtensions() {
return Collections.emptyList();
}
@Override
public Class<? extends RecordStore> getRecordStoreInterfaceClass(
final Map<String, ? extends Object> connectionProperties) {
return JdbcRecordStore.class;
}
@Override
public String getVendorName() {
return "postgresql";
}
@Override
public JdbcRecordStore newRecordStore(final DataSource dataSource) {
return new PostgreSQLRecordStore(dataSource);
}
@Override
public JdbcRecordStore newRecordStore(final Map<String, ? extends Object> connectionProperties) {
return new PostgreSQLRecordStore(this, connectionProperties);
}
@Override
public Map<String, Object> parseUrl(final String url) {
if (url != null && url.startsWith("jdbc:postgresql")) {
final Matcher hostMatcher = PATTERN_URL.matcher(url);
final Map<String, Object> parameters = new LinkedHashMap<>();
if (hostMatcher.matches()) {
parameters.put("recordStoreType", getName());
final Map<String, Object> urlParameters = UrlUtil.getQueryStringMap(hostMatcher.group(4));
parameters.putAll(urlParameters);
final String host = hostMatcher.group(1);
parameters.put("host", Strings.lowerCase(host));
final String port = hostMatcher.group(2);
parameters.put("port", port);
final String database = hostMatcher.group(3);
parameters.put("database", database);
parameters.put("namedConnection", null);
return parameters;
}
}
return Collections.emptyMap();
}
@Override
public String toString() {
return getName();
}
@Override
public String toUrl(final Map<String, Object> urlParameters) {
final StringBuilder url = new StringBuilder("jdbc:postgresql:");
final String host = Maps.getString(urlParameters, "host");
final Integer port = Maps.getInteger(urlParameters, "port");
final String database = Maps.getString(urlParameters, "database");
final boolean hasHost = Property.hasValue(host);
final boolean hasPort = port != null;
if (hasHost || hasPort) {
url.append("//");
if (hasHost) {
url.append(host);
}
if (hasPort) {
url.append(':');
url.append(port);
}
url.append('/');
}
if (Property.hasValue(database)) {
url.append(database);
}
return url.toString();
}
}