From: Thorsten K. <Tho...@pt...> - 2007-09-12 07:32:21
|
> Hello, >=20 > I have developed a Java web application based on Tomcat which reads = shape files and imports the geometries into a PostGis database. When = only a single user imports his data, then so far everything works very = well. But if two or more concurrent users want to import their shape = files, then the application crashes.=20 >=20 > The workflow is the following:=20 > A user loads a zip file up to the server. For each zip file, a random = directory name is created and the zip file is stored in it. After that = the file will get extracted and the shape file is imported into PostGis. = >=20 > The error scenario is the following: > For example user1 loads geo1.zip and user2 loads geo2.zip up to the = server. Then the two directories and files c:/abc/geo1.zip and = c:/cba/geo2.zip are created on the server's filesystem. Then the bug = comes: my shape file reader muddles up the directories and can't find = the files because it puts the paths together in a wrong way, e.g. = c:/abc/geo2.zip. >=20 > I dont't understand why the path is created in this wrong way because = the requests don't share the same instance of the class ShapeFileReader = (which is indeed nod thread safe), they create all their own instance.=20 > Perhaps an expert of you can help me to find my mistake! >=20 > Here is my code of the shape file reader: > ########################################### > public class ShapeFileReader { >=20 > private static Logger logger =3D = Logger.getLogger(ShapeFileReader.class);=20 > private URL shapeURL; > private ShapefileDataStore store; > private FeatureSource source; > private FeatureResults fsShape; > private FeatureReader reader; > =09 > /** > * This method initializes the object. > * @param path The path to the shape file. > */ > public synchronized void setShapeFilePath(String path) { > File file =3D new File(path); >=20 > try { > this.shapeURL =3D file.toURL(); > this.store =3D new ShapefileDataStore(this.shapeURL); > String name =3D store.getTypeNames()[0]; > this.source =3D this.store.getFeatureSource(name); > this.fsShape =3D this.source.getFeatures(); > this.reader =3D this.fsShape.reader(); > } ... /** > * This method collects the geometry values from the shape file. > * @see GeometryBean > * @return A Vector of type <code>GeometryBean</code> > */ > public synchronized Vector getGeometries() { > Vector geometries =3D new Vector(); > try { > this.reader =3D this.fsShape.reader(); >=20 > while (this.reader.hasNext()) { > Feature feature =3D this.reader.next(); > =09 > MultiPolygon polygon =3D (MultiPolygon) = feature.getDefaultGeometry(); > GeometryBean geometryBean =3D new GeometryBean(); > geometryBean.setMultiPolygon(polygon); > geometries.add(geometryBean); > } > } ... > return geometries; > } > ########################################### >=20 > Here is the relevant code of the servlet which starts the import = process: > ########################################### > public class ShapeImportServlet extends = javax.servlet.http.HttpServlet implements javax.servlet.Servlet { > protected void doPost(HttpServletRequest request, HttpServletResponse = response) throws ServletException, IOException { > // The information about the uploaded zip file, containing the = directory name and the zip file name > UploadDataBean uploadData =3D (UploadDataBean) = session.getAttribute("uploadData"); > this.processImport(request, uploadData); > ... > } > /** > * This method extracts the necessary information out of the request = and delegates > * the database import to a dedicated importer thread. So the servlet = can display > * the results immediately while the importer thread does its job. > * @param request HttpServletRequest. > * @param uploadData Information about the data which should be = uploaded. > */ > private void processImport(HttpServletRequest request, UploadDataBean = uploadData) > { >=20 > String directory =3D uploadData.getDirectoryName() + "/"; > =09 > Map parameters =3D request.getParameterMap(); > =09 > Set set =3D parameters.keySet(); > Iterator iter =3D set.iterator(); > =09 > ArrayList filePaths =3D new ArrayList(); > ArrayList tableNames =3D new ArrayList(); > =09 > ArrayList params =3D new ArrayList(); > =09 > //Evaluate the request parameters > for(Enumeration e=3Drequest.getParameterNames(); = e.hasMoreElements(); ) > { > params.add((String)e.nextElement()); > }=20 > =09 > String[] parameterNames =3D new String[params.size()]; > =09 > for (int i =3D 0; i < parameterNames.length; i++) { > parameterNames[i] =3D (String) params.get(i); > } > =09 > // Bring the parameter names in the right order to evaluate them = correctly. > // After sorting, the version, the pk ant the name match. > Arrays.sort(parameterNames); > for (int i =3D 0; i < parameterNames.length; i++) { > tableNames.add(request.getParameter(parameterNames[i])); > filePaths.add(directory + parameterNames[i]); > } > } > if (workflow.equals("1")) { > logger.info("User has chosen to process workflow 1"); > new Workflow1Thread(filePaths, tableNames, versions, pks, = countryID).start(); > } else { > System.out.println("---Begin DEBUG"); > for (int i =3D 0; i < filePaths.size(); i++) { > System.out.print("filepath " + (String)filePaths.get(i) + > " tableName " + (String) tableNames.get(i) +=20 > " version " + (String) versions.get(i) + "\n"); > } > new Workflow2Thread(filePaths, tableNames, versions, pks, = countryID).start(); > } > } > // This method in the workflow threads starts the reading and import = of the shape files: > protected void importGeometries() { > // for every geometry table which should be imported > for (int i =3D 0; i < this.pathToShapeFile.size(); i++) { > // ShapeFileAccess mit Pfad zum File benutzen, um die Eintraege zu = lesen > shapeFileAccess.setShapeFilePath((String) = this.pathToShapeFile.get(i)); // here the application gets a = FileNotFoundException!! > Vector geometries =3D shapeFileAccess.getGeometries(); > } > } > } > ########################################### > Regards, > Thorsten |