package com.revolsys.geopackage; import java.io.File; import java.nio.file.Path; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import javax.sql.DataSource; import org.sqlite.SQLiteJDBCLoader; import com.revolsys.collection.map.LinkedHashMapEx; import com.revolsys.collection.map.MapEx; import com.revolsys.collection.map.Maps; import com.revolsys.datatype.DataTypes; import com.revolsys.io.FileUtil; import com.revolsys.io.file.Paths; import com.revolsys.jdbc.io.JdbcDatabaseFactory; import com.revolsys.jdbc.io.JdbcRecordStore; import com.revolsys.record.io.FileRecordStoreFactory; import com.revolsys.record.schema.FieldDefinition; import com.revolsys.record.schema.RecordStore; import com.revolsys.spring.resource.UrlResource; import com.revolsys.util.Property; /** * jdbc:sqlite:[file] */ public class GeoPackage implements JdbcDatabaseFactory, FileRecordStoreFactory { static { try { SQLiteJDBCLoader.initialize(); } catch (final Throwable e) { // TODO Auto-generated catch block e.printStackTrace(); } } private static final List<String> FILE_NAME_EXTENSIONS = Arrays.asList("gpkg"); private static final List<Pattern> URL_PATTERNS = Arrays.asList(Pattern.compile("jdbc:sqlite:.+"), Pattern.compile("[^(file:)].+\\.gpkg"), Pattern.compile("file:(/(//)?)?.+\\.gpkg"), Pattern.compile("folderconnection:/(//)?.*.gpkg")); public static final String JDBC_PREFIX = "jdbc:sqlite:"; private static final List<FieldDefinition> CONNECTION_FIELD_DEFINITIONS = Arrays.asList( // new FieldDefinition("file", DataTypes.FILE, 50, true) // ); @Override public boolean canOpenPath(final Path path) { if (isAvailable()) { final String fileNameExtension = Paths.getFileNameExtension(path); return getRecordStoreFileExtensions().contains(fileNameExtension); } else { return false; } } @Override public boolean canOpenUrl(final String url) { if (isAvailable()) { for (final Pattern pattern : getUrlPatterns()) { if (pattern.matcher(url).matches()) { return true; } } } return false; } @Override public List<FieldDefinition> getConnectionFieldDefinitions() { return CONNECTION_FIELD_DEFINITIONS; } @Override public String getConnectionValidationQuery() { return null; } @Override public String getDriverClassName() { return "org.sqlite.JDBC"; } @Override public String getName() { return "GeoPackage Database"; } @Override public String getProductName() { return "GeoPackage"; } @Override public List<String> getRecordStoreFileExtensions() { return FILE_NAME_EXTENSIONS; } @Override public Class<? extends RecordStore> getRecordStoreInterfaceClass( final Map<String, ? extends Object> connectionProperties) { return JdbcRecordStore.class; } @Override public List<Pattern> getUrlPatterns() { return URL_PATTERNS; } @Override public String getVendorName() { return "sqlite"; } @Override public boolean isDirectory() { return false; } @Override public DataSource newDataSource(final Map<String, ? extends Object> config) { final MapEx newConfig = new LinkedHashMapEx(config); final String url = newConfig.getString("url"); if (Property.hasValue(url) && !url.startsWith("jdbc")) { try { final UrlResource resource = new UrlResource(url); final File file = resource.getFile(); final String newUrl = JDBC_PREFIX + FileUtil.getCanonicalPath(file); newConfig.put("url", newUrl); } catch (final Exception e) { throw new IllegalArgumentException(url + " must be a file", e); } } newConfig.put("enable_load_extension", true); return JdbcDatabaseFactory.super.newDataSource(newConfig); } @Override public JdbcRecordStore newRecordStore(final DataSource dataSource) { return new GeoPackageRecordStore(dataSource); } @Override public JdbcRecordStore newRecordStore(final Map<String, ? extends Object> connectionProperties) { return new GeoPackageRecordStore(this, connectionProperties); } @Override public Map<String, Object> parseUrl(final String url) { if (url != null && url.startsWith(JDBC_PREFIX)) { final Map<String, Object> parameters = new LinkedHashMap<>(); final String fileName = url.substring(JDBC_PREFIX.length()); parameters.put("recordStoreType", getName()); parameters.put("file", fileName); } return Collections.emptyMap(); } @Override public String toString() { return getName(); } @Override public String toUrl(final Map<String, Object> urlParameters) { final StringBuilder url = new StringBuilder(JDBC_PREFIX); final String file = Maps.getString(urlParameters, "file"); url.append(file); return url.toString().toLowerCase(); } }