geotools严重:以下锁定器仍然具有锁定读取文件

时间:2012-07-09 15:48:24

标签: java geotools

我正在使用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)

1 个答案:

答案 0 :(得分:1)

您需要在getCoordinateSystem()方法中关闭PrjFileReader:

private String getCoordinateSystem(String shpFilePath) throws MalformedURLException, IOException {
    PrjFileReader fileReader = null
    try {
        ShpFiles shapeFiles = new ShpFiles(shpFilePath);
        fileReader = new PrjFileReader(shapeFiles);
        CoordinateReferenceSystem coordSystem = fileReader.getCoodinateSystem();
        String coordType = coordSystem.getName().toString();
        return coordType;
    } finally {
        if (fileReader != null) {
            fileReader.close();
        }
    }
}