gcube-cms-suite/geoportal-service/src/main/java/org/gcube/application/geoportal/service/model/internal/db/PostgisTable.java

315 lines
9.9 KiB
Java

package org.gcube.application.geoportal.service.model.internal.db;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.gcube.application.geoportal.common.model.legacy.BBOX;
import org.gcube.application.cms.implementations.faults.DataParsingException;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
@RequiredArgsConstructor
@Getter
@ToString
public class PostgisTable {
@Getter
@AllArgsConstructor
public static enum GeometryType{
MULTIPOINT("4326","geometry (MULTIPOINT,4326)","",""),
POINT("4326","geometry (POINT,4326)","",""),
LINE("4326","geometry (MULTILINESTRING,4326)","",""),
POLYGON("4326","geometry (MULTIPOLYGON,4326)","","");
private final String SRID;
private final String definition;
private final String InsertWKT;
private final String insertWKB;
}
@RequiredArgsConstructor
@Getter
@ToString
public static class Field{
@NonNull
private String name;
@NonNull
private FieldType type;
private Boolean isIndexed;
private Object constantValue;
}
@Getter
@AllArgsConstructor
public enum FieldType{
INT("int",java.sql.Types.INTEGER),
TEXT("text",java.sql.Types.LONGVARCHAR),
FLOAT("float",java.sql.Types.FLOAT),
GEOMETRY("",0),
AUTOINCREMENT("BIGSERIAL PRIMARY KEY",java.sql.Types.BIGINT);
private String definition;
private int sqlType;
}
@RequiredArgsConstructor
@Getter
@ToString
public static class POINT{
private static Pattern pattern = Pattern.compile("(?!=\\d\\.\\d\\.)([\\d.]+)");
public static POINT parsePOINT(String point) throws DataParsingException {
//POINT(8.30230113965909 44.8011688237011)
// x,y
try {
log.debug("Parsing POINT "+point);
Matcher m=pattern.matcher(point);
if(!m.find()) throw new DataParsingException("Unable to get x ");
Double x=Double.parseDouble(m.group(1));
if(!m.find()) throw new DataParsingException("Unable to get y ");
Double y=Double.parseDouble(m.group(1));
return new POINT(x,y);
}catch(Throwable t) {
throw new DataParsingException("Invalid POINT "+point,t);
}
}
@NonNull
private Double x;
@NonNull
private Double y;
}
private static final NumberFormat DECIMAL_FORMAT=NumberFormat.getInstance(Locale.US);
static {
((DecimalFormat) DECIMAL_FORMAT).setGroupingUsed(false);
}
public String getGeometryColumn() {
for(Field f:fields)
if(f.getType().equals(FieldType.GEOMETRY)) return f.getName();
return null;
}
@NonNull
private String tablename;
@NonNull
private List<Field> fields;
@NonNull
private GeometryType geometryColumnType;
@Setter
private BBOX boundingBox=null;
@Setter
private POINT centroid=null;
public void setTablename(String tablename) {
this.tablename = sanitizeFieldName(tablename);
}
public String getCreateStatement() {
StringBuilder stmt=new StringBuilder();
stmt.append("CREATE TABLE IF NOT EXISTS "+tablename+"( ");
for(Field field:fields){
String fieldDefinition=field.getType().getDefinition();
if(field.getType().equals(FieldType.GEOMETRY))
fieldDefinition=this.getGeometryColumnType().definition;
stmt.append(field.getName()+" "+fieldDefinition+",");
}
stmt.deleteCharAt(stmt.lastIndexOf(","));
stmt.append(")");
return stmt.toString();
}
public String getDeleteByFieldStatement(Field field) {
return "DELETE FROM "+tablename+" WHERE "+field.getName()+" = ? ";
}
public String getInsertionStatement(boolean geometryText) {
StringBuilder fieldList=new StringBuilder();
StringBuilder fieldInsertion=new StringBuilder();
for(Field field:fields) {
switch(field.getType()) {
case AUTOINCREMENT : break;
case GEOMETRY : {
fieldList.append(field.getName()+",");
if(geometryText)
fieldInsertion.append("ST_GeomFromText(?, 4326),");
else
fieldInsertion.append("ST_GeomFromWKB(?, 4326),");
break;
}
default : {
fieldList.append(field.getName()+",");
fieldInsertion.append("?,");
}
}
}
fieldList.deleteCharAt(fieldList.lastIndexOf(","));
fieldInsertion.deleteCharAt(fieldInsertion.lastIndexOf(","));
return "Insert into "+tablename+" ("+fieldList+") VALUES ("+fieldInsertion+")";
}
public void fillObjectsPreparedStatement(Map<String,Object> row, PreparedStatement toFill) throws SQLException {
int psFieldIndex=0;
HashMap<String,Object> rowValues=new HashMap<String,Object>();
for(Map.Entry<String,Object> entry:row.entrySet())
rowValues.put(sanitizeFieldName(entry.getKey()), entry.getValue());
for(Field field:fields) {
if(!field.getType().equals(FieldType.AUTOINCREMENT)) {
psFieldIndex++;
Object value=rowValues.get(field.getName());
setObjectInPreparedStatement(field,value,toFill,psFieldIndex);
}
}
}
public void setObjectInPreparedStatement(Field field,Object value, PreparedStatement toFill, int psFieldIndex) throws SQLException {
if(value==null) {
try{
toFill.setNull(psFieldIndex, field.getType().sqlType);
}catch(SQLException e) {
log.error("Unable to set null for field "+field);
throw e;
}
}
else
switch(field.getType()) {
case FLOAT :{
toFill.setFloat(psFieldIndex, (Float)value);
break;
}
case INT : {
toFill.setInt(psFieldIndex, (Integer)value);
break;
}
case TEXT : {
toFill.setString(psFieldIndex, value.toString());
break;
}
case GEOMETRY : {
toFill.setBytes(psFieldIndex, (byte[])value);
}
}
}
public void fillCSVPreparedStatament(Map<String,String> row, PreparedStatement toFill,boolean explicitGeometry) throws SQLException {
int psFieldIndex=0;
HashMap<String,String> rowValues=new HashMap<String,String>();
for(Map.Entry<String,String> entry:row.entrySet())
rowValues.put(sanitizeFieldName(entry.getKey()), entry.getValue());
for(Field field:fields) {
if(!field.getType().equals(FieldType.AUTOINCREMENT)) {
psFieldIndex++;
String value=rowValues.get(field.getName());
// if(value==null||value.equalsIgnoreCase("null")) toFill.setNull(psFieldIndex, field.getType().sqlType);
// else
switch(field.getType()) {
case FLOAT :{
try{
toFill.setFloat(psFieldIndex, Float.parseFloat(value));
}catch(NumberFormatException e) {
throw new SQLException(field+" cannot be null. CSV Row is "+rowValues,e);
}
break;
}
case INT : {
try{
toFill.setInt(psFieldIndex, Integer.parseInt(value));
}catch(NumberFormatException e) {
log.warn("Skipping value for "+field+" row was "+rowValues,e);
toFill.setNull(psFieldIndex, java.sql.Types.INTEGER);
}
break;
}
case TEXT : {
toFill.setString(psFieldIndex, value.toString());
break;
}
case GEOMETRY : {
if(explicitGeometry) {
toFill.setString(psFieldIndex,value);
}else {
switch(geometryColumnType){
case POINT: {
String xRepresentation=DECIMAL_FORMAT.format(Double.parseDouble(rowValues.get(DBConstants.Defaults.XCOORD_FIELD)));
String yRepresentation=DECIMAL_FORMAT.format(Double.parseDouble(rowValues.get(DBConstants.Defaults.YCOORD_FIELD)));
toFill.setString(psFieldIndex, "POINT("+xRepresentation+" "+
yRepresentation+")");
break;
}
default :{
toFill.setString(psFieldIndex,rowValues.get("wkt"));
break;
}
}
}
break;
}
}
}
}
}
public static String sanitizeFieldName(String fieldName) {
// return fieldName.toLowerCase().replaceAll(" ", "_").replaceAll("\\.", "").replaceAll("-", "_").replaceAll("////","_");
return fieldName.toLowerCase().replaceAll("[^a-z0-9_\\\\]", "_");
}
}