Mercurial > dive4elements > river
view flys-artifacts/src/main/java/de/intevation/flys/utils/GeometryUtils.java @ 5779:ebec12def170
Datacage: Add a pool of builders to make it multi threadable.
XML DOM is not thread safe. Therefore the old implementation only allowed one thread
to use the builder at a time. As the complexity of the configuration
has increased over time this has become a bottleneck of the whole application
because it took quiet some time to build a result. Furthermore the builder code path
is visited very frequent. So many concurrent requests were piled up
resulting in long waits for the users.
To mitigate this problem a round robin pool of builders is used now.
Each of the pooled builders has an independent copy of the XML template
and can be run in parallel.
The number of builders is determined by the system property
'flys.datacage.pool.size'. It defaults to 4.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Sun, 21 Apr 2013 12:48:09 +0200 |
parents | fd07bcaff880 |
children |
line wrap: on
line source
package de.intevation.flys.utils; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import de.intevation.flys.model.RiverAxis; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.geotools.data.DataStoreFactorySpi; import org.geotools.data.DefaultTransaction; import org.geotools.data.FeatureWriter; import org.geotools.data.Transaction; import org.geotools.data.shapefile.ShapefileDataStore; import org.geotools.data.shapefile.ShapefileDataStoreFactory; import org.geotools.data.simple.SimpleFeatureIterator; import org.geotools.feature.FeatureCollection; import org.geotools.feature.FeatureIterator; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.geojson.feature.FeatureJSON; import org.geotools.geometry.jts.JTS; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; import org.hibernate.HibernateException; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; public class GeometryUtils { private static final Logger logger = Logger.getLogger(GeometryUtils.class); public static final String PREFIX_EPSG = "EPSG:"; public static final String DEFAULT_EPSG = "EPSG:31467"; private GeometryUtils() { } public static Envelope getRiverBoundary(String rivername) { try { List<RiverAxis> axes = RiverAxis.getRiverAxis(rivername); if (axes != null && axes.size() > 0) { Envelope max = null; for (RiverAxis axis: axes) { // TODO Take the correct EPSG into account. Maybe, we need to // reproject the geometry. Envelope env = axis.getGeom().getEnvelopeInternal(); if (max == null) { max = env; } else { max.expandToInclude(env); } } return max; } } catch(HibernateException iae) { logger.warn("No vaild river axis found for " + rivername); return null; } logger.warn("No vaild river axis found for " + rivername); return null; } public static String getRiverBounds(String rivername) { Envelope env = getRiverBoundary(rivername); if (env != null) { return jtsBoundsToOLBounds(env); } return null; } /** * Returns the boundary of Envelope <i>env</i> in OpenLayers representation. * * @param env The envelope of a geometry. * * @return the OpenLayers boundary of <i>env</i>. */ public static String jtsBoundsToOLBounds(Envelope env) { StringBuilder buf = new StringBuilder(); buf.append(env.getMinX()); buf.append(' '); buf.append(env.getMinY()); buf.append(' '); buf.append(env.getMaxX()); buf.append(' '); buf.append(env.getMaxY()); return buf.toString(); } public static String createOLBounds(Geometry a, Geometry b) { Coordinate[] ca = a.getCoordinates(); Coordinate[] cb = b.getCoordinates(); double lowerX = Double.MAX_VALUE; double lowerY = Double.MAX_VALUE; double upperX = -Double.MAX_VALUE; double upperY = -Double.MAX_VALUE; for (Coordinate c: ca) { lowerX = lowerX < c.x ? lowerX : c.x; lowerY = lowerY < c.y ? lowerY : c.y; upperX = upperX > c.x ? upperX : c.x; upperY = upperY > c.y ? upperY : c.y; } for (Coordinate c: cb) { lowerX = lowerX < c.x ? lowerX : c.x; lowerY = lowerY < c.y ? lowerY : c.y; upperX = upperX > c.x ? upperX : c.x; upperY = upperY > c.y ? upperY : c.y; } return "" + lowerX + " " + lowerY + " " + upperX + " " + upperY; } public static SimpleFeatureType buildFeatureType( String name, String srs, Class<?> geometryType) { return buildFeatureType(name, srs, geometryType, null); } /** * Creates a new SimpleFeatureType using a SimpleFeatureTypeBuilder. * * @param name The name of the FeatureType. * @param srs The SRS (e.g. "EPSG:31466"). * @param geometryType The geometry type's class (e.g. Polygon.class). * @param attrs Optional. An object with attribute-name/attribute-class pairs * where index 0 specifies the name as string and index 1 the * ype as class. * * @return a new SimpleFeatureType. */ public static SimpleFeatureType buildFeatureType(String name, String srs, Class<?> geometryType, Object[][] attrs) { try { SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder(); CoordinateReferenceSystem crs = CRS.decode(srs); builder.setName("flys"); builder.setNamespaceURI("http://www.intevation.de/"); builder.setCRS(crs); builder.setSRS(srs); builder.add("geometry", geometryType, crs); if (attrs != null) { for (Object[] attr: attrs) { builder.add((String) attr[0], (Class<?>) attr[1]); } } return builder.buildFeatureType(); } catch (NoSuchAuthorityCodeException nsae) { } catch (FactoryException fe) { } return null; } public static List<SimpleFeature> parseGeoJSON( String geojson, SimpleFeatureType ft ) { List<SimpleFeature> collection = new ArrayList<SimpleFeature>(); try { FeatureJSON fjson = new FeatureJSON(); fjson.setFeatureType(ft); FeatureIterator<SimpleFeature> iterator = fjson.streamFeatureCollection(geojson); while (iterator.hasNext()) { collection.add(iterator.next()); } } catch (IOException ioe) { // TODO handle exception } return collection; } /** * This method returns the {@link CoordinateReferenceSystem} by the * {@link String} <i>epsg</i>. * * @param epsg An EPSG code like <b>EPSG:31466</b> * * @return the {@link CoordinateReferenceSystem} specified by <i>epsg</i>. */ public static CoordinateReferenceSystem getCoordinateReferenceSystem( String epsg ) { if (epsg == null) { logger.warn("cannot create CoordinateReferenceSystem with null"); return null; } if (!epsg.startsWith(PREFIX_EPSG)) { epsg = PREFIX_EPSG + epsg; } try { return CRS.decode(epsg); } catch (FactoryException fe) { logger.error( "unable to get CoordinateReferenceSystem for: " + epsg, fe); } return null; } public static Envelope transform(Envelope orig, String targetSrs) { return transform(orig, targetSrs, DEFAULT_EPSG); } public static Envelope transform( Envelope orig, String targetSrs, String origSrs ) { if (targetSrs == null || orig == null || origSrs == null) { logger.warn("unable to transform envelope: empty parameters"); return orig; } logger.debug("Transform envlope to '" + targetSrs + "'"); try { CoordinateReferenceSystem sourceCRS = getCoordinateReferenceSystem(origSrs); CoordinateReferenceSystem targetCRS = getCoordinateReferenceSystem(targetSrs); if (sourceCRS != null && targetCRS != null) { ReferencedEnvelope tmpEnv = new ReferencedEnvelope(orig, CRS.decode(origSrs)); Envelope target = tmpEnv.transform(targetCRS, false); if (logger.isDebugEnabled()) { logger.debug(" orig envelope : " + orig); logger.debug(" transformed envelope: " + target); } return target; } } catch (NoSuchAuthorityCodeException nsae) { logger.error("Cannot get CoordinateReferenceSystem!", nsae); } catch (FactoryException fe) { logger.error("Cannot get CoordinateReferenceSystem!", fe); } catch (TransformException te) { logger.error("Cannot transform envelope from source " + origSrs + " to target srs " + targetSrs); } return null; } public static boolean writeShapefile(File shape, SimpleFeatureType featureType, FeatureCollection<?, ?> collection) { return writeShapefile(shape, featureType, collection, featureType.getCoordinateReferenceSystem()); } public static boolean writeShapefile(File shape, SimpleFeatureType featureType, FeatureCollection<?, ?> collection, CoordinateReferenceSystem crs) { if (collection.isEmpty()) { logger.warn("Shapefile is not written - no features given!"); return false; } Transaction transaction = null; try { MathTransform transform = CRS.findMathTransform( CRS.decode(DEFAULT_EPSG), crs); Map<String, Serializable> params = new HashMap<String, Serializable>(); params.put("url", shape.toURI().toURL()); params.put("create spatial index", Boolean.TRUE); DataStoreFactorySpi dataStoreFactory = new ShapefileDataStoreFactory(); ShapefileDataStore newDataStore = (ShapefileDataStore)dataStoreFactory.createNewDataStore(params); newDataStore.createSchema(featureType); transaction = new DefaultTransaction("create"); String typeName = newDataStore.getTypeNames()[0]; FeatureWriter<SimpleFeatureType, SimpleFeature> writer = newDataStore.getFeatureWriter(typeName, transaction); SimpleFeatureIterator iterator = (SimpleFeatureIterator) collection.features(); while (iterator.hasNext()){ SimpleFeature feature = iterator.next(); SimpleFeature copy = writer.next(); copy.setAttributes(feature.getAttributes()); Geometry orig = (Geometry) feature.getDefaultGeometry(); Geometry reprojected = JTS.transform(orig, transform); copy.setDefaultGeometry(reprojected); writer.write(); } transaction.commit(); return true; } catch (MalformedURLException mue) { logger.error("Unable to prepare shapefile: " + mue.getMessage()); } catch (IOException ioe) { logger.error("Unable to write shapefile: " + ioe.getMessage()); } catch (NoSuchAuthorityCodeException nsae) { logger.error("Cannot get CoordinateReferenceSystem for '" + DEFAULT_EPSG + "'"); } catch (FactoryException fe) { logger.error("Cannot get CoordinateReferenceSystem for '" + DEFAULT_EPSG + "'"); } catch (TransformException te) { logger.error("Was not able to transform geometry!", te); } finally { if (transaction != null) { try { transaction.close(); } catch (IOException ioe) { /* do nothing */ } } } return false; } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :