Java tutorial
/* * Copyright (C) 2007-2012 GeoSolutions S.A.S. * http://www.geo-solutions.it * * GPLv3 + Classpath exception * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package it.geosolutions.geobatch.destination.vulnerability; import it.geosolutions.geobatch.destination.common.InputObject; import it.geosolutions.geobatch.destination.common.OutputObject; import it.geosolutions.geobatch.destination.ingestion.MetadataIngestionHandler; import it.geosolutions.geobatch.destination.vulnerability.TargetManager.TargetInfo; import it.geosolutions.geobatch.destination.vulnerability.VulnerabilityMonitor.Message.TYPE; import it.geosolutions.geobatch.flow.event.ProgressListenerForwarder; import it.geosolutions.jaiext.bandmerge.BandMergeCRIF; import it.geosolutions.jaiext.bandmerge.BandMergeDescriptor; import it.geosolutions.jaiext.nullop.NullCRIF; import it.geosolutions.jaiext.nullop.NullDescriptor; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; import java.awt.image.DataBuffer; import java.awt.image.RenderedImage; import java.io.File; import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.ConcurrentSkipListSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.media.jai.BorderExtender; import javax.media.jai.ImageLayout; import javax.media.jai.JAI; import javax.media.jai.PlanarImage; import org.apache.commons.lang3.StringUtils; import org.geotools.coverage.grid.GridEnvelope2D; import org.geotools.coverage.grid.GridGeometry2D; import org.geotools.data.DefaultTransaction; import org.geotools.data.FeatureSource; import org.geotools.data.Transaction; import org.geotools.feature.FeatureCollection; import org.geotools.feature.FeatureIterator; import org.geotools.geometry.Envelope2D; import org.geotools.image.jai.Registry; import org.geotools.jdbc.JDBCDataStore; import org.geotools.referencing.operation.transform.AffineTransform2D; import org.jaitools.imageutils.ImageLayout2; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.filter.Filter; import org.opengis.geometry.MismatchedDimensionException; import org.opengis.metadata.spatial.PixelOrientation; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.datum.PixelInCell; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.NoninvertibleTransformException; import org.opengis.referencing.operation.TransformException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vividsolutions.jts.geom.Geometry; /** * This class is the entry point for the vulnerability process (method computeVulnerability) and it implements the computation's main loop * * @author DamianoG * @author Nicola Lagomarsini * @author Daniele Romagnoli, GeoSolutions SAS */ public class VulnerabilityComputation extends InputObject { public static final String JAI_EXT_PRODUCT = "it.geosolutions.jaiext.roiaware"; private static final int MAX_TEMP_CALC = 20; private static final int BBOX_COORD_NUM = 4; private final static Logger LOGGER = LoggerFactory.getLogger(VulnerabilityComputation.class); private static Pattern TYPE_NAME_PARTS = Pattern .compile("^([A-Z]{2})_([A-Z]{1})_([A-Za-z]+)_([0-9]{8})(_.*?)?$"); public static String GEO_TYPE_NAME = "siig_geo_ln_arco_X"; public static String VULNERABILITY_TYPE_NAME = "siig_t_vulnerabilita_X"; private static String DISTANCE_TYPE_NAME = "siig_d_distanza"; private static String ID_GEO_ARCO = "id_geo_arco"; public static String PARTNER_FIELD = "fk_partner"; public static String GEOID = "id_geo_arco"; public final static String RASTER_PATH_PROP = "SIIG_RASTERS_PATH"; private static final BorderExtender type = BorderExtender.createInstance(BorderExtender.BORDER_ZERO); private Long startOriginId; private Long endOriginId; private Long totPages; private Long pageNumber; private int pixelArea; private Map vulnerabilityCfg; String codicePartner; String date; int currentArc = 0; double currentDistance = 0; int partner; static { try { Registry.registerRIF(JAI.getDefaultInstance(), new BandMergeDescriptor(), new BandMergeCRIF(), JAI_EXT_PRODUCT); Registry.registerRIF(JAI.getDefaultInstance(), new NullDescriptor(), new NullCRIF(), JAI_EXT_PRODUCT); } catch (Throwable e) { // swallow exception in case the op has already been registered. } } /** * @param startOriginId the startOriginId to set */ public void setStartOriginId(Long startOriginId) { this.startOriginId = startOriginId; } /** * @param endOriginId the endOriginId to set */ public void setEndOriginId(Long endOriginId) { this.endOriginId = endOriginId; } /** * @param pixelArea the pixelArea to set */ public void setPixelArea(int pixelArea) { this.pixelArea = pixelArea; } /** * @param totPages the totPages to set */ public void setTotPages(Long totPages) { this.totPages = totPages; } /** * @param pageNumber the pageNumber to set */ public void setPageNumber(Long pageNumber) { this.pageNumber = pageNumber; } /** * @param inputTypeName * @param listenerForwarder */ public VulnerabilityComputation(String inputTypeName, ProgressListenerForwarder listenerForwarder, MetadataIngestionHandler metadataHandler, JDBCDataStore dataStore) { super(inputTypeName, listenerForwarder, metadataHandler, dataStore); // default area pixelArea = 100; } public int getPartner() { return partner; } public String getCodicePartner() { return codicePartner; } public String getDate() { return date; } public void removeVulnerabilityImports() throws IOException { removeOldImports(); } @Override protected String getInputTypeName(String inputTypeName) { return inputTypeName.replace("_ORIG", "").replace("_CALCS", ""); } @Override protected boolean parseTypeName(String typeName) { Matcher m = TYPE_NAME_PARTS.matcher(typeName); if (m.matches()) { // partner alphanumerical abbreviation (from siig_t_partner) codicePartner = m.group(1); // partner numerical id (from siig_t_partner) partner = Integer.parseInt(partners.get(codicePartner).toString()); date = m.group(4); return true; } return false; } private String getTypeName(String typeName, int aggregationLevel) { return typeName.replace("X", aggregationLevel + ""); } /** * Compute the vulnerability for each arc. The Algorithm is: * * ForEach(target) buffers = computeBuffers(allDistance, arc); ForEach(distance) if(!isAccepted(distance,target)) saveOnDB(0,arc,target,distance) * continue; sum = computeSum(buffer, target); ForEach(arc) saveOnDB(sum,arc,target,distance); * * * @param datastoreParams * @param crs * @param aggregationLevel * @param bbox * @throws IOException */ public void computeVulnerability(CoordinateReferenceSystem crs, int aggregationLevel, String writeMode, RenderedImage currentImage, Map<Integer, TargetInfo> currentBPT, String targetID, int minTileX, int maxTileX, int minTileY, int maxTileY, boolean skipArcs, Integer xStart, Integer yStart, Integer xStop, Integer yStop, String idStart, Envelope2D bbox, VulnerabilityMonitor monitor, ConcurrentSkipListSet<BigDecimal> arcIdsSet) throws IOException { reset(); // Initial checks if (isValid()) { crs = checkCrs(crs); String outFeatureName = getTypeName(VULNERABILITY_TYPE_NAME, aggregationLevel); // // Load All needed resources: properties files, Rendered Images, // GeotifReaders // // final TargetPropertiesLoader propertiesLoader = new TargetPropertiesLoader(); vulnerabilityCfg = (Map) readResourceFromXML("/vulnerability.xml"); String basePath = System.getProperty(RASTER_PATH_PROP, ""); if (!basePath.equals("")) { basePath = basePath + File.separator + codicePartner; } VulnerabilityStatsEngine vse = new VulnerabilityStatsEngine(basePath, vulnerabilityCfg, dataStore, DISTANCE_TYPE_NAME, pixelArea); // Setup the OutputObject (in thet case the vulnerability table) // remove old values for the partner and detect the max id Transaction transaction = new DefaultTransaction(); OutputObject vulnerabilityObj = new OutputObject(dataStore, transaction, outFeatureName, GEOID); VulnerabilityOperation concreteOperation; // Human targets if (targetID.equalsIgnoreCase("Human")) { // // Load the concrete operation (Update) // concreteOperation = prepareVulnerabilityOperation("UPDATE", vulnerabilityObj); // Not Human targets } else { // // Load the concrete operation (Insert or PurgeInsert) // concreteOperation = prepareVulnerabilityOperation(writeMode, vulnerabilityObj); } // // Start the vulnerability Computation // try { List<Double> allDistances = vse.getDistances(); int reportingLoopStep = allDistances.size() > 10 ? 50 : 100; // setup geo input / output object String geoName = getTypeName(GEO_TYPE_NAME, aggregationLevel); if (aggregationLevel == 3) { geoName = geoName.replace("ln", "pl"); } // Creation of the input reader createInputReader(dataStore, null, geoName); Filter partnerFilter = filterFactory.equals(filterFactory.property(PARTNER_FIELD), filterFactory.literal(partner)); setInputFilter(partnerFilter); LOGGER.info("Start computation: ThreadName: " + Thread.currentThread().getName() + " - startOriginId: " + startOriginId + " - endOriginId: " + endOriginId); // Setting of the monitor parameters try { if (aggregationLevel != 3) { // Vulnerability computation for the level 1 or 2 vulnerabilityLevel12(currentImage, currentBPT, targetID, minTileX, maxTileX, minTileY, maxTileY, skipArcs, xStart, yStart, xStop, yStop, idStart, bbox, outFeatureName, monitor.getTrace(), vse, transaction, vulnerabilityObj, concreteOperation, monitor, allDistances, reportingLoopStep, geoName, arcIdsSet); } else { // Vulnerability computation for the level 3 vulnerabilityLevel3(currentImage, currentBPT, targetID, bbox, outFeatureName, monitor.getTrace(), vse, vulnerabilityObj, concreteOperation, monitor, allDistances, reportingLoopStep, geoName, partnerFilter, arcIdsSet); } } catch (Exception e) { monitor.incrementErrors(); monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.ERROR, "Raster=" + targetID + ", Error occurred on raster: " + targetID + " for distance " + currentDistance + " on arc:" + currentArc, e)); LOGGER.error("Raster=" + targetID + ", Error occurred on raster: " + targetID + " for distance " + currentDistance + " on arc:" + currentArc + "\n" + e.getMessage(), e); } } finally { closeInputReader(); LOGGER.info( "Write errors for " + targetID + ": " + (monitor.getErrors() - monitor.getStartErrors())); monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.CLOSE)); transaction.close(); } } } /** * This method calculates the vulnerability for the levels 1 and 2 * * @param currentImage * @param currentBPT * @param keySet * @param targetID * @param minTileX * @param maxTileX * @param minTileY * @param maxTileY * @param skipArcs * @param xStart * @param yStart * @param xStop * @param yStop * @param idStart * @param bbox * @param outFeatureName * @param trace * @param vse * @param statsMap * @param transaction * @param vulnerabilityObj * @param concreteOperation * @param monitor * @param inputFeature * @param allDistances * @param reportingLoopStep * @param geoName * @param total * @throws NoninvertibleTransformException * @throws TransformException * @throws IOException */ private void vulnerabilityLevel12(RenderedImage currentImage, Map<Integer, TargetInfo> currentBPT, String targetID, int minTileX, int maxTileX, int minTileY, int maxTileY, boolean skipArcs, Integer xStart, Integer yStart, Integer xStop, Integer yStop, String idStart, Envelope2D bbox, String outFeatureName, int trace, VulnerabilityStatsEngine vse, Transaction transaction, OutputObject vulnerabilityObj, VulnerabilityOperation concreteOperation, VulnerabilityMonitor monitor, List<Double> allDistances, int reportingLoopStep, String geoName, ConcurrentSkipListSet<BigDecimal> arcIdsSet) throws NoninvertibleTransformException, TransformException, IOException { // Preliminary checks if (minTileX > maxTileX) { int temp = minTileX; minTileX = maxTileX; maxTileX = temp; } if (minTileY > maxTileY) { int temp = minTileY; minTileY = maxTileY; maxTileY = temp; } // Load the Transformation associated with the selected // target and calculate the inverse TargetInfo firstInfo = currentBPT.get(0); MathTransform w2g = firstInfo.getGG2D().getCRSToGrid2D(PixelOrientation.UPPER_LEFT); MathTransform g2w = w2g.inverse(); // Load the target dimensions for modifying the spatial // filter // Definition of the dimensions associated to the input image int tileWidth = currentImage.getTileWidth(); int tileHeight = currentImage.getTileHeight(); int tileGridX = currentImage.getTileGridXOffset(); int tileGridY = currentImage.getTileGridYOffset(); // Variables used for mapping the tile in the model space // Iteration on image tiles for (int x = minTileX; x < maxTileX; x++) { // For each tile, the points are transformed in the // world crs int minX = PlanarImage.tileXToX(x, tileGridX, tileWidth); if (xStart != null && xStart > x) { continue; } if (xStop != null && xStop < x) { continue; } for (int y = minTileY; y < maxTileY; y++) { int minY = PlanarImage.tileYToY(y, tileGridY, tileHeight); if (yStart != null && yStart > y) { continue; } if (yStop != null && yStop < y) { continue; } Envelope2D worldEnvelope = calculateWorldEnvelope(minX, minY, tileWidth, tileHeight, g2w); calculateTile(worldEnvelope, bbox, x, y, xStart, yStart, idStart, concreteOperation, monitor, arcIdsSet, vse, currentBPT, allDistances, currentImage, targetID, outFeatureName, vulnerabilityObj); } } } private Envelope2D calculateWorldEnvelope(int minX, int minY, int tileWidth, int tileHeight, MathTransform g2w) throws TransformException { double[] srcPts = new double[BBOX_COORD_NUM]; double[] dstPts = new double[BBOX_COORD_NUM]; // Source Coordinates srcPts[0] = minX; srcPts[1] = minY; srcPts[2] = minX + tileWidth; srcPts[3] = minY + tileHeight; // Coordinates transformation g2w.transform(srcPts, 0, dstPts, 0, 2); // Creation of the BoundingBox associated with // the selected tile double height = Math.abs(dstPts[1] - dstPts[3]); double width = Math.abs(dstPts[0] - dstPts[2]); // Setting of the bounding box Envelope2D env = new Envelope2D(); env.x = dstPts[0]; env.y = dstPts[3]; env.height = height; env.width = width; return env; } private void calculateBatch(int batchSize, ConcurrentSkipListSet<BigDecimal> arcIdsSet, VulnerabilityStatsEngine vse, List<Double> allDistances, Map<Integer, TargetInfo> currentBPT, VulnerabilityMonitor monitor, RenderedImage currentImage, String targetID, int x, int y, VulnerabilityOperation concreteOperation, String outFeatureName, OutputObject vulnerabilityObj) { // Initialize lists of the calculated arcs for this batch List<SimpleFeature> arcList = new ArrayList<SimpleFeature>(); List<String> arcIds = new ArrayList<String>(); List<MultipleBufferMap> bufferList = new ArrayList<MultipleBufferMap>(); List<ResultStatsMap> statList = new ArrayList<ResultStatsMap>(); // we calculate a batch of batchSize features at a time calculateBuffersOnBatch(batchSize, arcIdsSet, vse, allDistances, monitor, targetID, x, y, arcList, arcIds, bufferList); // Operations are executed only if there is at least one arc if (!arcList.isEmpty()) { try { // Iteration on all the buffers for (Double processedDistance : allDistances) { // Update of the currentDistance variable for exception logging currentDistance = processedDistance; // Check if the distance is // related to the selected // target // Empty map used for containing // only the accepted targets Map<Integer, TargetInfo> acceptedBands = mapAcceptedBands(currentBPT, processedDistance); // Statistical computation // The statistics are calculated // only if almost one of the // targets accepts the current // distance boolean bandAccepted = !acceptedBands.isEmpty(); if (bandAccepted) { // Number of ResultStatsMap // already present int statListSize = statList.size(); // Number of buffer to // calculate int buffListSize = bufferList.size(); // If the ResultStatsMap are // not enough, they are // calculated until they // reach the desired // number if (statListSize < buffListSize) { int difference = buffListSize - statListSize; for (int i = 0; i < difference; i++) { statList.add(new ResultStatsMap(vulnerabilityCfg)); } } for (ResultStatsMap stats : statList) { stats.initStatsMap(acceptedBands); } // extract all the buffers for current distance for all the arcs in current batch List<Geometry> geometryList = calculateGeometryList(bufferList, processedDistance); // Compute Stats for all buffers -> Vulnerability try { vse.computeStats(geometryList, currentImage, statList, false, acceptedBands); } catch (Exception e) { monitor.incrementErrors(); monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.ERROR, "Raster=" + targetID + ", TILE=(" + x + "," + y + ") Error calculating stats on batch of arcs: " + StringUtils.join(arcIds, ","), e)); LOGGER.error("Raster=" + targetID + ", TILE=(" + x + "," + y + ") Error calculating stats on batch of arcs: " + StringUtils.join(arcIds, ","), e); } } // Iteration on all the // geometries list for (int i = 0; i < arcList.size(); i++) { // Selection of the arc SimpleFeature arc = arcList.get(i); // Selection of the arcId String arcId = arcIds.get(i); // ResultStatsMap associated // with the arc ResultStatsMap resMap; if (bandAccepted) { resMap = statList.get(i); } else { resMap = new ResultStatsMap(vulnerabilityCfg); resMap.initStatsMap(new HashMap<Integer, TargetInfo>()); } try { // Writing of the result // for the selected // distance and Id concreteOperation.writeOutputObjects(monitor.getTrace(), vulnerabilityObj, monitor.getTotal(), outFeatureName, arc, buildFid(arcId, processedDistance), resMap.getStatsMap(), partner); // DEBUG: indication of // which arc is // calculated if (LOGGER.isDebugEnabled()) { LOGGER.debug("Raster=" + targetID + ", TILE=(" + x + "," + y + ") Computed arc " + arcId + " for distance=" + processedDistance); } } catch (Exception e) { monitor.incrementErrors(); monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.ERROR, "Raster=" + targetID + ", TILE=(" + x + "," + y + ") Error writing objects on " + outFeatureName + ": Computed arc " + arcId + " for distance=" + processedDistance, e)); LOGGER.error("Raster=" + targetID + ", TILE=(" + x + "," + y + ") Error writing objects on " + outFeatureName + ": Computed arc " + arcId + " for distance=" + processedDistance, e); } } } monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.PROGRESS, "Calculating vulnerability for " + targetID)); for (int i = 0; i < arcList.size(); i++) { monitor.incrementCounter(); } } catch (Exception e) { monitor.incrementErrors(); monitor.newMessage( new VulnerabilityMonitor.Message(TYPE.ERROR, "Raster=" + targetID + ", TILE=(" + x + "," + y + ") Error computing batch of arcs", e)); LOGGER.error("Raster=" + targetID + ", TILE=(" + x + "," + y + ") Error computing batch of arcs", e); } } } /** * Calculate all the buffers geometries for the next batchSize set of arcs. * * @param batchSize * @param arcIdsSet * @param vse * @param allDistances * @param monitor * @param targetID * @param x * @param y * @param arcList * @param arcIds * @param bufferList * @return */ private int calculateBuffersOnBatch(int batchSize, ConcurrentSkipListSet<BigDecimal> arcIdsSet, VulnerabilityStatsEngine vse, List<Double> allDistances, VulnerabilityMonitor monitor, String targetID, int x, int y, List<SimpleFeature> arcList, List<String> arcIds, List<MultipleBufferMap> bufferList) { int batchCounter = 0; try { while (batchCounter < batchSize && hasMoreInput(true)) { SimpleFeature inputFeature = readInput(); BigDecimal arcId = ((BigDecimal) inputFeature.getAttribute(ID_GEO_ARCO)); // Check if the feature has been already // taken boolean newArc = arcIdsSet.add(arcId); if (newArc) { try { MultipleBufferMap mbm = vse.computeBuffersOnArcs(Collections.singletonList(inputFeature), allDistances); bufferList.add(mbm); arcList.add(inputFeature); arcIds.add(arcId.toString()); } catch (Exception e) { monitor.incrementErrors(); monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.ERROR, "Error calculating buffers for arc " + arcId, e)); LOGGER.error("Error calculating buffers for arc " + arcId, e); } } batchCounter++; } } catch (Exception e1) { monitor.incrementErrors(); monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.ERROR, "Raster=" + targetID + ", TILE=(" + x + "," + y + ") Error reading arcs", e1)); LOGGER.error("Raster=" + targetID + ", TILE=(" + x + "," + y + ") Error reading arcs batch", e1); } return batchCounter; } private void calculateTile(Envelope2D env, Envelope2D bbox, int x, int y, Integer xStart, Integer yStart, String idStart, VulnerabilityOperation concreteOperation, VulnerabilityMonitor monitor, ConcurrentSkipListSet<BigDecimal> arcIdsSet, VulnerabilityStatsEngine vse, Map<Integer, TargetInfo> currentBPT, List<Double> allDistances, RenderedImage currentImage, String targetID, String outFeatureName, OutputObject vulnerabilityObject) { // Creation of a spatial filter for taking only // the features associated // to the selected bounding box if ((xStart != null && x == xStart) && (yStart != null && y == yStart) && idStart != null) { setInputFilter( concreteOperation.buildOriginFilterExtended(partner, monitor.getTotal(), env, bbox, idStart)); } else { setInputFilter( concreteOperation.buildOriginFilterExtended(partner, monitor.getTotal(), env, bbox, null)); } try { while (hasMoreInput(true)) { calculateBatch(MAX_TEMP_CALC, arcIdsSet, vse, allDistances, currentBPT, monitor, currentImage, targetID, x, y, concreteOperation, outFeatureName, vulnerabilityObject); } } catch (Exception e) { monitor.incrementErrors(); monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.ERROR, "Raster=" + targetID + ", TILE=(" + x + "," + y + ") Generic error", e)); LOGGER.error("Raster=" + targetID + ", TILE=(" + x + "," + y + ") Generic error", e); } } /** * This method calculates the vulnerability for the level 3 * * @param currentImage * @param currentBPT * @param keySet * @param targetID * @param bbox * @param outFeatureName * @param trace * @param vse * @param vulnerabilityObj * @param concreteOperation * @param monitor * @param allDistances * @param reportingLoopStep * @param geoName * @param partnerFilter * @param total * @throws IOException */ private void vulnerabilityLevel3(RenderedImage currentImage, Map<Integer, TargetInfo> currentBPT, String targetID, Envelope2D bbox, String outFeatureName, int trace, VulnerabilityStatsEngine vse, OutputObject vulnerabilityObj, VulnerabilityOperation concreteOperation, VulnerabilityMonitor monitor, List<Double> allDistances, int reportingLoopStep, String geoName, Filter partnerFilter, ConcurrentSkipListSet<BigDecimal> arcIdsSet) throws IOException { SimpleFeature currentCell; // Setting of the input filter BigDecimal idCellStart = new BigDecimal(startOriginId); BigDecimal idCellStop = new BigDecimal(endOriginId); concreteOperation.setStartOriginId(idCellStart.longValue()); concreteOperation.setEndOriginId(idCellStop.longValue()); // Creation of the input filter used setInputFilter(concreteOperation.buildOriginFilterExtended(partner, monitor.getTotal(), null, bbox, null)); try { while ((currentCell = readInputSorted()) != null) { calculateCell(currentImage, currentBPT, targetID, outFeatureName, trace, vse, vulnerabilityObj, concreteOperation, monitor, allDistances, reportingLoopStep, geoName, partnerFilter, arcIdsSet, currentCell); } } catch (Exception e) { monitor.incrementErrors(); monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.ERROR, "Raster=" + targetID + ", TILE=(" + idCellStart + "," + idCellStop + ") Generic error", e)); LOGGER.error("Raster=" + targetID + ", CELLS=(" + idCellStart + "," + idCellStop + ") Generic error", e); } //monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.FINISH, "Vulnerability calculation completed")); } private void calculateCell(RenderedImage currentImage, Map<Integer, TargetInfo> currentBPT, String targetID, String outFeatureName, int trace, VulnerabilityStatsEngine vse, OutputObject vulnerabilityObj, VulnerabilityOperation concreteOperation, VulnerabilityMonitor monitor, List<Double> allDistances, int reportingLoopStep, String geoName, Filter baseFilter, ConcurrentSkipListSet<BigDecimal> arcIdsSet, SimpleFeature currentCell) { // Selection of the id associated to the feature. BigDecimal cellId = ((BigDecimal) currentCell.getAttribute(ID_GEO_ARCO)); // Check if the feature has been already taken boolean newCell = arcIdsSet.add(cellId); if (newCell) { Map<Double, ResultStatsMap> statList = new TreeMap<Double, ResultStatsMap>(); // For level 3, get all the arcs that intersect with // the current grid cell FeatureIterator<SimpleFeature> iterator = null; try { iterator = getArcsForCell(geoName, baseFilter, currentCell); while (iterator.hasNext()) { calculateBetchOfArcsForCell(currentImage, currentBPT, vse, allDistances, statList, iterator, cellId.toString(), MAX_TEMP_CALC, monitor, targetID); } } catch (Exception e) { monitor.incrementErrors(); monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.ERROR, "Raster=" + targetID + ", Error reading arcs for cell " + cellId, e)); LOGGER.error("Raster=" + targetID + ", Error reading arcs for cell " + cellId, e); } finally { if (iterator != null) { iterator.close(); } } // write cell stats for (Double processedDistance : allDistances) { try { // Writing of the result for the // selected distance and Id concreteOperation.writeOutputObjects(trace, vulnerabilityObj, monitor.getTotal(), outFeatureName, currentCell, buildFid(cellId.toString(), processedDistance), statList.get(processedDistance).getStatsMap(), partner); } catch (Exception e) { monitor.incrementErrors(); monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.ERROR, "Raster=" + targetID + ", Error writing cell " + cellId + " on " + geoName, e)); LOGGER.error("Raster=" + targetID + ", Error writing objects on " + geoName, e); } } // Update of the LoopCounter monitor.incrementCounter(); monitor.newMessage( new VulnerabilityMonitor.Message(TYPE.PROGRESS, "Calculating vulnerability for " + targetID)); // DEBUG: indication of which arc is calculated if (LOGGER.isDebugEnabled() && currentCell != null) { LOGGER.debug("Raster=" + targetID + ", Computed cell " + cellId); } } } private FeatureIterator<SimpleFeature> getArcsForCell(String geoName, Filter partnerFilter, SimpleFeature currentCell) throws IOException { FeatureIterator<SimpleFeature> iterator; // Cell element Geometry cell = (Geometry) currentCell.getDefaultGeometry(); String linearGeoName = geoName.replace("pl", "ln"); FeatureSource<SimpleFeatureType, SimpleFeature> reader = createInputReader(dataStore, null, linearGeoName); // Iterator for selecting all the geometries // intersecting the cell Filter featureFilter = filterFactory.and( filterFactory.intersects(filterFactory.property(getInputGeometryName(dataStore, linearGeoName)), filterFactory.literal(cell)), partnerFilter); FeatureCollection<SimpleFeatureType, SimpleFeature> features = reader.getFeatures(featureFilter); iterator = features.features(); return iterator; } private void calculateBetchOfArcsForCell(RenderedImage currentImage, Map<Integer, TargetInfo> currentBPT, VulnerabilityStatsEngine vse, List<Double> allDistances, Map<Double, ResultStatsMap> statList, FeatureIterator<SimpleFeature> iterator, String cellId, int batchSize, VulnerabilityMonitor monitor, String targetID) throws Exception { List<SimpleFeature> arcList = new ArrayList<SimpleFeature>(); Set<String> arcIds = new HashSet<String>(); // Temporary counter used for calculating only a fixed number of geometries for each time int batchArcsCounter = 0; while (batchArcsCounter < batchSize && iterator.hasNext()) { SimpleFeature sf = (SimpleFeature) iterator.next(); // addition of the simple feature to the // list arcList.add(sf); arcIds.add(sf.getAttribute(ID_GEO_ARCO).toString()); batchArcsCounter++; } // BUFFER CALCULATION // If at least an arc is present if (!arcList.isEmpty()) { try { MultipleBufferMap mbm = vse.computeBuffersOnArcs(arcList, allDistances); for (Double processedDistance : allDistances) { // Update of the currentDistance variable for exception logging currentDistance = processedDistance; // Creation of the ResultStatsMap for the selected distance if not present if (!statList.containsKey(processedDistance)) { statList.put(processedDistance, new ResultStatsMap(vulnerabilityCfg)); } // Check if the distance is related // to the selected target Map<Integer, TargetInfo> acceptedBands = mapAcceptedBands(currentBPT, processedDistance); // Statistics computation // The statistics are calculated // only if at least one of the targets // accepts the current distance if (!acceptedBands.isEmpty()) { try { vse.computeStats(mbm.getBuffersForDistance(processedDistance), currentImage, statList.get(processedDistance), false, acceptedBands); } catch (Exception e) { monitor.incrementErrors(); monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.ERROR, "Raster=" + targetID + ", CELL=(" + cellId + ") Error calculating stats on batch of arcs: " + StringUtils.join(arcIds, ","), e)); LOGGER.error("Raster=" + targetID + ", CELL=(" + cellId + ") Error calculating stats on batch of arcs: " + StringUtils.join(arcIds, ","), e); } } } } catch (Exception e) { monitor.incrementErrors(); monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.ERROR, "Raster=" + targetID + ", CELL=(" + cellId + ") Error calculating buffers for arc " + StringUtils.join(arcIds, ","), e)); LOGGER.error("Raster=" + targetID + ", CELL=(" + cellId + ") Error calculating buffers for arcs " + StringUtils.join(arcIds, ","), e); } } } /** * Private method used for preparing the vulnerability operation associated to the input write mode * * @param writeMode * @param vulnerabilityObj * @return * @throws IOException */ private VulnerabilityOperation prepareVulnerabilityOperation(String writeMode, OutputObject vulnerabilityObj) throws IOException { VulnerabilityOperation concreteOperation = VulnerabilityOperation.instantiateWriterFromString(writeMode); LOGGER.info("Using writer " + VulnerabilityOperation.class); concreteOperation.initFeature(vulnerabilityObj, partner); // Setup filtering concreteOperation.setStartOriginId(startOriginId); concreteOperation.setEndOriginId(endOriginId); concreteOperation.setPageNumber(pageNumber); concreteOperation.setTotPages(totPages); return concreteOperation; } /** * Remove the initial features if the writeMode parameter is PURGE_INSERT * * @param writeMode * @param aggregationLevel * @throws IOException */ public void removeFeatures(String writeMode, int aggregationLevel) throws IOException { if (writeMode.equalsIgnoreCase("PURGE_INSERT")) { // Selection of the type name String outFeatureName = getTypeName(VULNERABILITY_TYPE_NAME, aggregationLevel); // Creation of a new Transaction Transaction transaction = new DefaultTransaction(); try { // Preparing of the Purge_Insert operation which removes all the features already present OutputObject vulnerabilityObj = new OutputObject(dataStore, transaction, outFeatureName, GEOID); prepareVulnerabilityOperation(writeMode, vulnerabilityObj); } finally { // Closing Transaction transaction.close(); } } } /** * Private method used for checking if the input feature has been already calculated. * * @param targetID * @param skipArcs * @param outFeatureName * @param transaction * @param inputFeature * @param featureSize * @return * @throws IOException */ /*private int checkInputFeature(String targetID, boolean skipArcs, String outFeatureName, Transaction transaction, SimpleFeature inputFeature, int featureSize) throws IOException { if (inputFeature != null && skipArcs && targetID.equalsIgnoreCase("NotHuman")) { // Selection of the id associated to the // feature. BigDecimal arcId = ((BigDecimal) inputFeature.getAttribute(ID_GEO_ARCO)); if (!FeatureLoaderUtils .createFeatureSource(dataStore, transaction, outFeatureName) .getFeatures( filterFactory.equals(filterFactory.property(GEOID), filterFactory.literal(arcId))).isEmpty()) { featureSize = 0; } } return featureSize; }*/ /** * Private method which returns the Geometry list associated to the processed distance * * @param bufferList * @param processedDistance * @return */ private static List<Geometry> calculateGeometryList(List<MultipleBufferMap> bufferList, Double processedDistance) { List<Geometry> geometryList = new ArrayList<Geometry>(); // Addition of the buffer // associated with the // selected distance and arc for (MultipleBufferMap mbm : bufferList) { // Use the cell for crop // the raster if the // aggregation level == // 3, use the buffer // otherwise Geometry bufferArea = (Geometry) mbm.getBuffersForDistance(processedDistance).get(0); geometryList.add(bufferArea); } return geometryList; } /** * Private method for writing the results on the Database for the level 3 * * @param targetID * @param outFeatureName * @param trace * @param errors * @param vulnerabilityObj * @param concreteOperation * @param inputFeature * @param allDistances * @param geoName * @param total * @param idArco * @param statList * @return * @throws IOException private int writeResultsOnDB(String targetID, String outFeatureName, int trace, int errors, OutputObject vulnerabilityObj, VulnerabilityOperation concreteOperation, SimpleFeature inputFeature, List<Double> allDistances, String geoName, String idArco, Map<Double, ResultStatsMap> statList, VulnerabilityMonitor monitor) throws IOException { // Iteration on all the buffers for (Double processedDistance : allDistances) { try { // Writing of the result for the // selected distance and Id concreteOperation.writeOutputObjects(trace, vulnerabilityObj, monitor.getTotal(), outFeatureName, inputFeature, buildFid(idArco, processedDistance), statList .get(processedDistance).getStatsMap(), partner); } catch (Exception e) { monitor.incrementErrors(); monitor.newMessage(new VulnerabilityMonitor.Message(TYPE.ERROR, "Raster=" + targetID + ", Error writing objects on " + geoName, e)); LOGGER.error("Raster=" + targetID + ", Error writing objects on " + geoName, e); } } return errors; }*/ /** * Method which returns a map for all the accepted bands for the processed distance * * @param inputAcceptedBands * @param currentBPT * @param processedDistance * @return */ private Map<Integer, TargetInfo> mapAcceptedBands(Map<Integer, TargetInfo> currentBPT, Double processedDistance) { Map<Integer, TargetInfo> acceptedBands = new TreeMap<Integer, TargetManager.TargetInfo>(); // Set of all the bands Set<Integer> keys = currentBPT.keySet(); // Cycle on all the targets for (int band : keys) { // Selection of the // TargetInfo TargetInfo infoPerBand = currentBPT.get(band); // TargetManager associated TargetManager mng = infoPerBand.getManager(); // If the distance is // related to the target, // then it is added to the // map of the accepted band if (mng.isDistanceRelatedToTarget(processedDistance)) { acceptedBands.put(band, infoPerBand); } } return acceptedBands; } /** * Build the Fid associated to the arcId * * @param idArco * @param el * @return */ private static String buildFid(String idArco, Double el) { return idArco + "." + el.intValue(); } /** * Method used for merging the input Rasters into a 2 images, one for human targets and the other for not human targets * * @param humanTargets * @param notHumanTargets * @param bandPerTargetH * @param bandPerTargetNH * @throws IOException * @throws java.awt.geom.NoninvertibleTransformException * @throws TransformException * @throws MismatchedDimensionException */ public RenderedImage[] rasterCalculation(Map<Integer, TargetInfo> bandPerTargetH, Map<Integer, TargetInfo> bandPerTargetNH) throws IOException, java.awt.geom.NoninvertibleTransformException, MismatchedDimensionException, TransformException { // Initialization of the images RenderedImage humanTargets = null; RenderedImage notHumanTargets = null; String basePath = System.getProperty(RASTER_PATH_PROP, ""); if (!basePath.equals("")) { basePath = basePath + File.separator + codicePartner; } // Read of the resources Map vulnerabilityConf = (Map) readResourceFromXML("/vulnerability.xml"); // Vulnerability engine used for extracting the Targets VulnerabilityStatsEngine vsengine = new VulnerabilityStatsEngine(basePath, vulnerabilityConf, dataStore, DISTANCE_TYPE_NAME, pixelArea); // Target Map Map<String, TargetInfo> targetInfo = vsengine.getTargetInfo(); /* * Creation of 2 images: one for the HUMAN TARGETS and the other for NOT HUMAN TARGETS */ // List of Human Targets List<RenderedImage> humanList = new ArrayList<RenderedImage>(); // List of Not Human Targets List<RenderedImage> notHumanList = new ArrayList<RenderedImage>(); // Counters indicating which band is associated to the TargetInfo and // Image int humanBandCounter = 0; int notHumanBandCounter = 0; // Iterator on all the targets Iterator<String> rasterIter = targetInfo.keySet().iterator(); // Initializations of the parameters for merging the input rasters Envelope2D globalBBOXHuman = null; Envelope2D globalBBOXNotHuman = null; List<AffineTransform> tfHuman = new ArrayList<AffineTransform>(); List<AffineTransform> tfNotHuman = new ArrayList<AffineTransform>(); AffineTransform g2WHuman = null; AffineTransform g2WNotHuman = null; // Cycle on all the rasters while (rasterIter.hasNext()) { // save the ID of this target String targetID = rasterIter.next(); // Load the target manager, init its status and check if the actual // distance is a valid distance for it TargetInfo info = targetInfo.get(targetID); // Getting of the transformation parameters GridGeometry2D gg2D = info.getGG2D(); Envelope2D envelope = gg2D.getEnvelope2D(); AffineTransform w2g = (AffineTransform) gg2D.getCRSToGrid2D(PixelOrientation.UPPER_LEFT); // getting information about current Target TargetManager manager = info.getManager(); // Image associated to the current target RenderedImage newImage = info.getRaster(); // Image data type int imgDataType = newImage.getSampleModel().getDataType(); // Check if the image really exists if (newImage != null) { // If the target is human if (manager.isHumanTarget()) { // Other check for ensuring the target is correct if (imgDataType != DataBuffer.TYPE_FLOAT) { System.out.println("Wrong data type"); } // perform union if (globalBBOXHuman == null) { globalBBOXHuman = new Envelope2D(envelope); } else { globalBBOXHuman.include(envelope); } // Selection of the first g2w transform as the global one if (g2WHuman == null) { g2WHuman = (AffineTransform) gg2D.getGridToCRS2D(PixelOrientation.UPPER_LEFT); } // Creation of the transformation from destination Raster space to source Raster space AffineTransform temp = new AffineTransform(w2g); temp.concatenate(g2WHuman); tfHuman.add(temp); // Addition of the TargetInfo of this target bandPerTargetH.put(humanBandCounter, info); // Update of the bandCounter humanBandCounter++; // Addition of the image to the associated list humanList.add(newImage); } else { // Other check for ensuring the target is correct if (imgDataType != DataBuffer.TYPE_BYTE) { System.out.println("Wrong data type"); } // perform union if (globalBBOXNotHuman == null) { globalBBOXNotHuman = envelope; } else { globalBBOXNotHuman.include(envelope); } // Selection of the first g2w transform as the global one if (g2WNotHuman == null) { g2WNotHuman = (AffineTransform) gg2D.getGridToCRS2D(PixelOrientation.UPPER_LEFT); } // Creation of the transformation from destination Raster space to source Raster space AffineTransform temp = new AffineTransform(w2g); temp.concatenate(g2WNotHuman); tfNotHuman.add(temp); // Addition of the TargetInfo of this target bandPerTargetNH.put(notHumanBandCounter, info); // Update of the bandCounter notHumanBandCounter++; // Addition of the image to the associated list notHumanList.add(newImage); } } } // computing final raster space for the two targets GridGeometry2D humanGG2D = new GridGeometry2D(PixelInCell.CELL_CORNER, new AffineTransform2D(g2WHuman), globalBBOXHuman, null); globalBBOXHuman = humanGG2D.getEnvelope2D(); // take into account integer pixel roundings GridGeometry2D noHumanGG2D = new GridGeometry2D(PixelInCell.CELL_CORNER, new AffineTransform2D(g2WNotHuman), globalBBOXNotHuman, null); globalBBOXNotHuman = noHumanGG2D.getEnvelope2D(); // take into account integer pixel roundings // BandMerge of the images RenderedImage[] imagesHuman = new RenderedImage[humanList.size()]; RenderedImage[] imagesNotHuman = new RenderedImage[notHumanList.size()]; // Setting of the final layout ImageLayout layoutH = new ImageLayout2(); GridEnvelope2D gridRange2D = humanGG2D.getGridRange2D(); layoutH.setMinX(gridRange2D.x); layoutH.setMinY(gridRange2D.y); layoutH.setWidth(gridRange2D.width); layoutH.setHeight(gridRange2D.height); // Definition of the TileCache RenderingHints hintsH = new RenderingHints(JAI.KEY_TILE_CACHE, JAI.getDefaultInstance().getTileCache()); // Setting of the layout as hint hintsH.put(JAI.KEY_IMAGE_LAYOUT, layoutH); // Merging of the input human targets humanTargets = BandMergeDescriptor.create(null, 0, hintsH, tfHuman, humanList.toArray(imagesHuman)); // Setting of the final layout ImageLayout layoutNH = new ImageLayout2(); gridRange2D = noHumanGG2D.getGridRange2D(); layoutNH.setMinX(gridRange2D.x); layoutNH.setMinY(gridRange2D.y); layoutNH.setWidth(gridRange2D.width); layoutNH.setHeight(gridRange2D.height); // Definition of the TileCache RenderingHints hintsNH = new RenderingHints(JAI.KEY_TILE_CACHE, JAI.getDefaultInstance().getTileCache()); hintsNH.put(JAI.KEY_IMAGE_LAYOUT, layoutNH); // Merging of the input not human targets notHumanTargets = BandMergeDescriptor.create(null, 0, hintsNH, tfNotHuman, notHumanList.toArray(imagesNotHuman)); // cache the final images humanTargets = NullDescriptor.create(humanTargets, new RenderingHints(JAI.KEY_TILE_CACHE, JAI.getDefaultInstance().getTileCache())); notHumanTargets = NullDescriptor.create(notHumanTargets, new RenderingHints(JAI.KEY_TILE_CACHE, JAI.getDefaultInstance().getTileCache())); // Clearing of the initial lists notHumanList.clear(); humanList.clear(); // create a new array of the new images return new RenderedImage[] { humanTargets, notHumanTargets }; } /** * Method used for extracting the cells from this vulnerability object. If a cell ID is set and skipArcs is true, then only the cells which are * greater than that selected are used. * * @param cellStart * @param skipArcs * @return * @throws IOException */ public FeatureCollection<SimpleFeatureType, SimpleFeature> geometryIDList(String cellStart, boolean skipArcs) throws IOException { // Define the aggregation level int aggregationLevel = 3; // setup geo input / output object String geoName = getTypeName(GEO_TYPE_NAME, aggregationLevel); geoName = geoName.replace("ln", "pl"); createInputReader(dataStore, null, geoName); // Setting of the input filter // Simple filter on the partner Filter filter = filterFactory.equals(filterFactory.property(PARTNER_FIELD), filterFactory.literal(partner)); // Needed if the user restart the computation from the cellStart id if (skipArcs && cellStart != null) { filter = filterFactory.and(filter, filterFactory.greaterOrEqual(filterFactory.property(GEOID), filterFactory.literal(cellStart))); } setInputFilter(filter); FeatureCollection<SimpleFeatureType, SimpleFeature> cells = readCollectionSorted(); return cells; } }