/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wms.map; import java.awt.geom.NoninvertibleTransformException; import java.util.logging.Level; import java.util.logging.Logger; import org.geotools.renderer.GTRenderer; import org.geotools.renderer.RenderListener; import org.geotools.util.logging.Logging; import org.opengis.feature.IllegalAttributeException; import org.opengis.feature.simple.SimpleFeature; import org.opengis.referencing.FactoryException; import org.opengis.referencing.operation.TransformException; /** * A {@link RenderListener} that knows which rendering exceptions are ignorable and stops * rendering if not. * <p> * This map producer should register an instance of this listener to the renderer in order to * get notified of an unexpected rendering exception through the {@link #getException()} method. * </p> * <p> * The following exception causes are going to be ignored, any other one will stop the * rendering: * <ul> * <li> {@link IllegalAttributeException}: known to be thrown when a Feature attribute does not * validate against it's schema. * <li> {@link TransformException}: a geometry can't be transformed to the target CRS, usually * because of being outside the target CRS area of validity. * <li> {@link FactoryException}: the transform from source CRS to destination CRS and from there * to the display failed. * <li> {@link NoninvertibleTransformException}: a transformation error for geometry decimation * </ul> * </p> */ public class RenderExceptionStrategy implements RenderListener { private static final Logger LOGGER = Logging.getLogger("org.geoserver.wms"); private final GTRenderer renderer; private Exception renderException; /** * Creates a render listener to stop the given {@code renderer} when a non ignorable * exception is notified * * @param renderer * the renderer to {@link GTRenderer#stopRendering() stop} if a non * ignorable exception occurs */ public RenderExceptionStrategy(final GTRenderer renderer) { this.renderer = renderer; this.renderException = null; } /** * Tells whether a non ignorable exception occurred and hence the rendering process was * aborted * * @return {@code true} if rendering aborted due to an exception, {@code false} otherwise */ public boolean exceptionOccurred() { return renderException != null; } /** * @return the non ignorable exception occurred on the rendering loop, or {@code null} if * the renderer finished successfully. */ public Exception getException() { return renderException; } /** * Upon a render exception check if its cause is one that we actually want to ignore, and if * not abort the rendering process so the map producer can fail. */ public void errorOccurred(final Exception renderException) { Throwable cause = renderException; while (cause != null) { if (cause instanceof TransformException || cause instanceof IllegalAttributeException || cause instanceof FactoryException || cause instanceof NoninvertibleTransformException) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "Ignoring renderer error", renderException); } return; } cause = cause.getCause(); } // not an ignorable cause... stop rendering LOGGER.log(Level.FINE, "Got an unexpected render exception.", renderException); this.renderException = renderException; renderer.stopRendering(); } /** * Not used, we're only checking exceptions here * * @see RenderListener#featureRenderer(SimpleFeature) */ public void featureRenderer(SimpleFeature feature) { // intentionally left blank } }