我正在使用 geotools 从 shapefile 中提取数据并将它们存储到 mysql 中。我的应用程序一直在工作,但我经常得到这个锁,我不明白为什么,因为它仍然有效
[root@website-qc filespool]# /usr/bin/java -jar /opt/mcmap/library/Application/geotools/mcgeotools.jar -t publisher -i 1/194/Namibia_SCLB12.shp -rid 12 -s
app get cmd option cast to int: 12
app passing region id to runconvert: 12
runconvert rid passed: 12
Jul 9, 2012 4:23:48 PM org.geotools.data.db2.DB2DataStoreFactory isAvailable
INFO: DB2 driver found: true
Database connection acquired
Coordinates length: 5390
Coordinates length: 5358
Coordinates length: 9932
Jul 9, 2012 4:28:14 PM org.geotools.data.shapefile.ShpFiles logCurrentLockers
SEVERE: The following locker still has a lock� read on file:/opt/mcmap/public/filespool/1/194/Namibia_SCLB12.prj by org.geotools.data.shapefile.prj.PrjFileReader
it was created with the following stack trace
org.geotools.data.shapefile.ShpFilesLocker$Trace: Locking file:/opt/mcmap/public/filespool/1/194/Namibia_SCLB12.prj for read by org.geotools.data.shapefile.prj.PrjFileReader in thread main
at org.geotools.data.shapefile.ShpFilesLocker.setTraceException(ShpFilesLocker.java:72)
at org.geotools.data.shapefile.ShpFilesLocker.<init>(ShpFilesLocker.java:36)
at org.geotools.data.shapefile.ShpFiles.acquireRead(ShpFiles.java:365)
at org.geotools.data.shapefile.ShpFiles.getReadChannel(ShpFiles.java:813)
at org.geotools.data.shapefile.prj.PrjFileReader.<init>(PrjFileReader.java:66)
at com.domain.mcgeotools.convert.Converter.getCoordinateSystem(Converter.java:521)
at com.domain.mcgeotools.convert.Converter.runConvert(Converter.java:106)
at com.domain.mcgeotools.App.main(App.java:158)
Coordinates length: 5741
Coordinates length: 5374
Coordinates length: 4193
Coordinates length: 14161
Coordinates length: 5375
Coordinates length: 4212
下面是我的应用程序代码
package com.domain.mcgeotools.convert;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.File;
import java.net.ConnectException;
import java.net.MalformedURLException;
import java.util.Properties;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.sql.*;
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFinder;
import org.geotools.data.FeatureSource;
import org.geotools.data.shapefile.*;
import org.geotools.data.shapefile.prj.PrjFileReader;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.simple.SimpleFeatureImpl;
import org.opengis.feature.Property;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
public class Converter {
protected String filePath = null;
private Properties configFile = null;
private String[] acceptedCoordinateSytems = {
"Lat Long for MAPINFO type 0 Datum",
"GCS_WGS_1984"
};
private HashMap sqlStatements = new HashMap();
private int sqlCounter = 0;
public Converter() throws IOException {
/**
* We load the configuration details from the properties file and use the config. The config property
* item stores things such as database connection details etc.
*/
this.configFile = new Properties();
this.configFile.load(this.getClass().getClassLoader().getResourceAsStream("mcgeotools-config.properties"));
}
protected void setFilePath(String filePath) {
this.filePath = filePath;
}
protected String getFilePath() {
return this.filePath;
}
/**
* Converts the passed shape files and place the data into the RDBMS
*
* @param filePath
* @param verbose
* @param shrink
* @return
* @throws Exception
*/
public int runConvert(String filePath, int regionId, boolean verbose, boolean shrink, String type) throws Exception {
System.out.println("runconvert rid passed: " + regionId);
ShapeFile shapeFile = new ShapeFile();
if (!shapeFile.isShapeFile(filePath)) {
System.out.println(filePath);
throw new Exception("Not a shape file");
}
//we get the coordinate type from the shape file
String coordinateSystem = null;
try {
coordinateSystem = this.getCoordinateSystem(filePath);
if (verbose) {
//Print to console.
System.out.println("Coordinate System: " + coordinateSystem + " for " + filePath);
}
} catch (Exception cse) {
Logger.getLogger(Converter.class.getName()).log(Level.SEVERE, null, cse);
}
boolean acceptedSystem = false;
for (int i = 0; i < this.acceptedCoordinateSytems.length; i++) {
if (this.acceptedCoordinateSytems[i].equalsIgnoreCase(coordinateSystem)) {
acceptedSystem = true;
}
}
if (!acceptedSystem) {
throw new Exception("Not an excepted Coordinate System.");
}
//we now load the shapefile into the application
File file = new File(filePath);
if (file == null) {
throw new Exception("Failed to open " + filePath);
}
Map connect = new HashMap();
connect.put("url", file.toURI().toURL());
DataStore dataStore = DataStoreFinder.getDataStore(connect);
String[] typeNames = dataStore.getTypeNames();
String typeName = typeNames[0];
FeatureSource featureSource = dataStore.getFeatureSource(typeName);
FeatureCollection collection = featureSource.getFeatures();
FeatureIterator iterator = collection.features();
//database connection
Connection dbConn = null;
int surveyDbId = 0;
String localhostname = java.net.InetAddress.getLocalHost().getHostName();
try {
String dbUser = "", dbPwd = "", dbUrl = "";
dbUser = this.configFile.getProperty("DB_USER");
dbPwd = this.configFile.getProperty("DB_PASSWORD");
dbUrl = "jdbc:" + this.configFile.getProperty("DB_CONNSTR");
dbUrl = "jdbc:mysql://"+ localhostname +"/mcdatabase";
// If publishing overite connection strings
if(type.equals("publish")){
dbUser = this.configFile.getProperty("DB_PB_USER");
dbPwd = this.configFile.getProperty("DB_PB_PASSWORD");
dbUrl = "jdbc:" + this.configFile.getProperty("DB_PB_CONNSTR");
}
Class.forName("com.mysql.jdbc.Driver").newInstance();
dbConn = DriverManager.getConnection(dbUrl, dbUser, dbPwd);
System.out.println("Database connection acquired");
//switch off auto commits so that we run this as one transaction.
dbConn.setAutoCommit(false);
this.sqlStatements.put(this.sqlCounter, "START TRANSACTION");
this.sqlCounter++;
PreparedStatement surveyStmt = null;
ResultSet rs = null;
if(type.equals("convert")){
//insert data in to the survey table and get the last row ID.
surveyStmt = dbConn.prepareStatement("INSERT INTO surveys (name, guid, date_added, region_id, shrink) VALUES( ?, md5(now()), now(), ?, ? )");
surveyStmt.setString(1, typeName.replaceAll("%20", " "));
surveyStmt.setInt(2, regionId);
surveyStmt.setBoolean(3, shrink);
surveyStmt.executeUpdate();
rs = surveyStmt.getGeneratedKeys();
rs.first();
surveyDbId = rs.getInt(1);
this.sqlStatements.put(this.sqlCounter, "INSERT INTO surveys (name, guid, date_added, region_id, shrink) VALUES( '"+ typeName.replaceAll("%20", " ") +"', md5(now()), now(), "+ regionId +", "+ shrink +")");
}else if(type.equals("publish")){
//insert data in to the survey table and get the last row ID.
surveyStmt = dbConn.prepareStatement("INSERT INTO surveys (name, guid, published, date_added, region_id, shrink) VALUES( ?, md5(now()), 1, now(), ?, ? )");
surveyStmt.setString(1, typeName.replaceAll("%20", " "));
surveyStmt.setInt(2, regionId);
surveyStmt.setBoolean(3, shrink);
surveyStmt.executeUpdate();
rs = surveyStmt.getGeneratedKeys();
rs.first();
surveyDbId = rs.getInt(1);
this.sqlStatements.put(this.sqlCounter, "INSERT INTO surveys (name, guid, published, date_added, region_id, shrink) VALUES( '"+ typeName.replaceAll("%20", " ") +"', md5(now()), 1, now(), "+ regionId +", "+ shrink +")");
}
this.sqlCounter++;
rs.close();
surveyStmt.close();
//Total lat/long values to work center point.
double totalLat = 0.0;
double totalLong = 0.0;
int totalLongLats = 0;
while (iterator.hasNext()) {
SimpleFeatureImpl feature = (SimpleFeatureImpl) iterator.next();
Geometry sourceGeometry = (Geometry) feature.getDefaultGeometry();
//we now need to enter a link between the survey and the line data.
PreparedStatement lineStmt = null;
String lineStmtSQL = "INSERT INTO `lines` (guid, date_added, survey_id) VALUES (md5(now()), now(), ?)";
lineStmt = dbConn.prepareCall(lineStmtSQL);
lineStmt.setInt(1, surveyDbId);
lineStmt.executeUpdate();
ResultSet lineRS = lineStmt.getGeneratedKeys();
lineRS.first();
int lineDbId = lineRS.getInt(1);
this.sqlStatements.put(this.sqlCounter, "INSERT INTO `lines` (guid, date_added, survey_id) VALUES (md5(now()), now(), " +
surveyDbId +")");
this.sqlCounter++;
lineRS.close();
lineStmt.close();
//we now look for the properties of the line that we are about to process.
Collection<Property> coll = feature.getProperties();
Iterator colIterator = coll.iterator();
//we now look at inserting the line properties into the database.
PreparedStatement linePropStmt = null;
String linePropSQL = "INSERT INTO line_properties(`key`, `value`, `line_id`) VALUES(?, ?, ?)";
linePropStmt = dbConn.prepareStatement(linePropSQL);
while (colIterator.hasNext()) {
Property geoProp = (Property) colIterator.next();
if (verbose) {
System.out.println("prop name: " + geoProp.getName() + " Value: " + geoProp.getValue());
}
if (geoProp.getValue() != null && !geoProp.getName().toString().equals("the_geom")) {
//we then prepare the statment and execute for each property.
linePropStmt.setString(1, geoProp.getName().toString());
linePropStmt.setString(2, geoProp.getValue().toString());
linePropStmt.setInt(3, lineDbId);
linePropStmt.executeUpdate();
//add to sql command hashmap
this.sqlStatements.put(this.sqlCounter, "INSERT INTO line_properties(`key`, `value`, `line_id`) VALUES('" +
geoProp.getName().toString()+"', '"+
geoProp.getValue().toString()+"', "+lineDbId+")");
this.sqlCounter++;
}
}
//close the prepared statement now that we've finished with it.
linePropStmt.close();
//finally we populate the line coordinates into the database.
Coordinate[] coordinates = sourceGeometry.getCoordinates();
String lineName = feature.getID();
if (verbose) {
System.out.println(lineName);
}
PreparedStatement coordStmt = null;
String coordSQL = "INSERT INTO coordinates(`x`, `y`, line_id, sequence) VALUES(?, ?, ?, ?)";
coordStmt = dbConn.prepareStatement(coordSQL);
PreparedStatement lineStringStmt = null;
String longLatSQL = "UPDATE `lines` SET longlat_string = ? WHERE line_id = ?";
lineStringStmt = dbConn.prepareStatement(longLatSQL);
/**
* Used to build a full long lat string for fast lookups
* when being used in KML/Google Maps
*/
String longLatString = "";
boolean first = true;
int shotCount = 0;
System.out.println("Coordinates length: "+ coordinates.length);
for (int i = 0; i < coordinates.length; i++) {
if (verbose) {
System.out.println("x: " + coordinates[i].x + " - Y: " + coordinates[i].y);
}
//add to the long lat counter to find center point
totalLat += coordinates[i].x;
totalLong += coordinates[i].y;
totalLongLats++;
coordStmt.setString(1, Double.toString(coordinates[i].x));
coordStmt.setString(2, Double.toString(coordinates[i].y));
coordStmt.setInt(3, lineDbId);
coordStmt.setInt(4, i);
coordStmt.executeUpdate();
this.sqlStatements.put(this.sqlCounter, "INSERT INTO coordinates(`x`, `y`, line_id, sequence) VALUES('"+
Double.toString(coordinates[i].x) +"', '"+
Double.toString(coordinates[i].y) +"', "+lineDbId+", "+i+")");
this.sqlCounter++;
//now we build/update a string for the full coordinates.
if (first) {
longLatString = Double.toString(coordinates[i].x) + "," + Double.toString(coordinates[i].y);
first = false;
} else {
// Not implemented function fully, to strip long lats to start and end points only
if(shrink){
if(i == (coordinates.length -1)){
longLatString += ",0 " + Double.toString(coordinates[i].x) + "," + Double.toString(coordinates[i].y);
}
}else{
/* // testing this if
if( coordinates.length < 10 && shotCount == 2 ){
longLatString += ",0 " + Double.toString(coordinates[i].x) + "," + Double.toString(coordinates[i].y);
shotCount = 0;
}else */
//if( coordinates.length >= 10 && coordinates.length < 30 && shotCount == 4 ){
if( coordinates.length < 30 && shotCount == 4 ){
longLatString += ",0 " + Double.toString(coordinates[i].x) + "," + Double.toString(coordinates[i].y);
shotCount = 0;
}else if( coordinates.length >= 30 && coordinates.length < 100 && shotCount == 9 ){
longLatString += ",0 " + Double.toString(coordinates[i].x) + "," + Double.toString(coordinates[i].y);
shotCount = 0;
}else if( coordinates.length >= 100 && coordinates.length < 1000 && shotCount == 49 ){
longLatString += ",0 " + Double.toString(coordinates[i].x) + "," + Double.toString(coordinates[i].y);
shotCount = 0;
}else if( coordinates.length >= 1000 && coordinates.length < 10000 && shotCount == 99 ){
longLatString += ",0 " + Double.toString(coordinates[i].x) + "," + Double.toString(coordinates[i].y);
shotCount = 0;
}else if( coordinates.length >= 10000 && shotCount == 199 ){
longLatString += ",0 " + Double.toString(coordinates[i].x) + "," + Double.toString(coordinates[i].y);
shotCount = 0;
}
// Make sure to get last co-ordinate of line
if( i == (coordinates.length-1) ){ // -1 since coutn starts from zero
longLatString += ",0 " + Double.toString(coordinates[i].x) + "," + Double.toString(coordinates[i].y);
System.out.println("Last coordinate stored: " + longLatString);
shotCount = 0;
}
}
}
shotCount ++;
}
/**
* Update the line table to include the precreated line string.
*/
lineStringStmt.setString(1, longLatString);
lineStringStmt.setInt(2, lineDbId);
lineStringStmt.executeUpdate();
this.sqlStatements.put(this.sqlCounter, "UPDATE `lines` SET longlat_string = '"+longLatString+"' WHERE line_id = " + lineDbId);
this.sqlCounter++;
lineStringStmt.close();
coordStmt.close();
}
//finally we update the center point
PreparedStatement centerPointStmt = null;
String centerPointSQL = "UPDATE `surveys` SET center_point = ? WHERE survey_id = ?";
centerPointStmt = dbConn.prepareStatement(centerPointSQL);
double centerLat = totalLat/totalLongLats;
double centerLong = totalLong/totalLongLats;
String centerPoint = Double.toString(centerLat) + ", " + Double.toString(centerLong);
centerPointStmt.setString(1, centerPoint);
centerPointStmt.setInt(2, surveyDbId);
centerPointStmt.executeUpdate();
centerPointStmt.close();
this.sqlStatements.put(this.sqlCounter, "UPDATE `surveys` SET center_point = '"+centerPoint+"' WHERE survey_id = "+surveyDbId);
this.sqlCounter++;
//we now commit the transaction
dbConn.commit();
//now we can close the database connection.
dbConn.close();
this.sqlStatements.put(this.sqlCounter,"COMMIT");
this.sqlCounter++;
BufferedWriter out = new BufferedWriter(new java.io.FileWriter(this.configFile.getProperty("SQL_FILE").toString()));
for(int i = 0; i < this.sqlStatements.size(); i++){
out.write(this.sqlStatements.get(i) + ";" + "\n");
}
//close file connection
out.close();
System.out.println("End transaction");
} catch (Exception ex) {
System.out.println();
System.out.println("Message: "+ex.getMessage());
if(ex.getMessage().trim().contains("Communications link failure")){
System.out.println("Check there is a mysql connection and retry");
System.out.println();
System.exit(0);
}else{
Logger.getLogger(Converter.class.getName()).log(Level.SEVERE, null, ex);
//we've errored so we need to toll back the connection.
dbConn.rollback();
//we now insert a message into the audit log.
String auditSQL = "INSERT INTO auditlog (username, date_added, message, guid, type)" + "VALUES('mcgeotools', now(), ?, md5(now()), ?)";
PreparedStatement auditStmt = dbConn.prepareStatement(auditSQL);
//we want to know which survey failed to import and we need the stacktrace message.
String auditMessage = "Error whilst populating Survey " + typeName + " with error message : " + ex.getMessage();
auditStmt.setString(1, auditMessage);
auditStmt.setString(2, "error"); //error
auditStmt.execute();
dbConn.commit();
}
} finally {
//close the iterator
iterator.close();
//commit any transaction and close the connection to the database if it is open.
if (dbConn != null && !dbConn.isClosed()) {
try {
dbConn.commit();
dbConn.close();
} catch (Exception dbex) {
System.out.println("Communications failure, check there is a connection to mysql");
Logger.getLogger(Converter.class.getName()).log(Level.SEVERE, null, dbex);
}
}
//close file connection
}
return surveyDbId;
}
/**
* Get the coordinate system that is used in the shape file
*
* @param String shpFilePath
* @return String
*/
private String getCoordinateSystem(String shpFilePath) throws MalformedURLException, IOException {
String coordType = null;
ShpFiles shapeFiles = new ShpFiles(shpFilePath);
PrjFileReader fileReader = new PrjFileReader(shapeFiles);
CoordinateReferenceSystem coordSystem = fileReader.getCoodinateSystem();
coordType = coordSystem.getName().toString();
return coordType;
}
}
@Andre 错误
Feb 22, 2013 12:03:54 PM org.geotools.data.shapefile.ng.files.ShpFiles logCurrentLockers
SEVERE: The following locker still has a lock: read on file:/tmp/24/FozDoAmazonasPhase2.shp by org.geotools.data.shapefile.ng.shp.ShapefileReader
Feb 22, 2013 12:03:54 PM org.geotools.data.shapefile.ng.files.ShpFiles logCurrentLockers
SEVERE: The following locker still has a lock: read on file:/tmp/24/FozDoAmazonasPhase2.shx by org.geotools.data.shapefile.ng.shp.IndexFile
Feb 22, 2013 12:03:54 PM org.geotools.data.shapefile.ng.files.ShpFiles logCurrentLockers
SEVERE: The following locker still has a lock: read on file:/tmp/24/FozDoAmazonasPhase2.dbf by org.geotools.data.shapefile.ng.dbf.DbaseFileReader
Feb 22, 2013 12:04:39 PM com.spectrumasa.mcgeotools.App main
SEVERE: null
java.lang.IllegalArgumentException: Expected requestor org.geotools.data.shapefile.ng.dbf.DbaseFileReader@1966c114 to have locked the url but it does not hold the lock for the URL
at org.geotools.data.shapefile.ng.files.ShpFiles.unlockRead(ShpFiles.java:433)
at org.geotools.data.shapefile.ng.files.FileChannelDecorator.implCloseChannel(FileChannelDecorator.java:149)
at java.nio.channels.spi.AbstractInterruptibleChannel.close(AbstractInterruptibleChannel.java:114)
at org.geotools.data.shapefile.ng.dbf.DbaseFileReader.close(DbaseFileReader.java:279)
at org.geotools.data.shapefile.ng.ShapefileFeatureReader.close(ShapefileFeatureReader.java:248)
at org.geotools.data.store.ContentFeatureCollection$WrappingFeatureIterator.close(ContentFeatureCollection.java:227)
at com.spectrumasa.mcgeotools.convert.Converter.runConvert(Converter.java:487)
at com.spectrumasa.mcgeotools.App.main(App.java:100)