/* (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.wcs.response; import static org.geoserver.ows.util.ResponseUtils.baseURL; import static org.geoserver.ows.util.ResponseUtils.buildSchemaURL; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; import java.util.List; import java.util.logging.Level; import javax.servlet.http.HttpServletResponse; import org.geoserver.config.GeoServer; import org.geoserver.ows.DefaultServiceExceptionHandler; import org.geoserver.ows.Request; import org.geoserver.ows.ServiceExceptionHandler; import org.geoserver.ows.util.OwsUtils; import org.geoserver.ows.util.ResponseUtils; import org.geoserver.ows.xml.v1_0.OWS; import org.geoserver.platform.Service; import org.geoserver.platform.ServiceException; /** * An implementation of {@link ServiceExceptionHandler} which outputs * as service exception in a <code>ServiceExceptionReport</code> document. * <p> * This handler is referred to as "legacy" as newer services move to the ows * style exception report. See {@link DefaultServiceExceptionHandler}. * </p> * <p> * <h3>Version</h3> * By default this exception handler will output a <code>ServiceExceptionReport</code> * which is of version <code>1.2.0</code>. This may be overriden with * {@link #setVersion(String)}. * </p> * <p> * <h3>DTD and Schema</h3> * By default, no DTD or XML Schema reference will be included in the document. * The methods {@link #setDTDLocation(String)} and {@link #setSchemaLocation(String)} * can be used to override this behaviour. Only one of these methods should be * set per instance of this class. * * The supplied value should be relative, and will be appended to the result * of {@link OWS#getSchemaBaseURL()}. * </p> * <p> * <h3>Content Type</h3> * The default content type for the created document is <code>text/xml</code>, * this can be overridden with {@link #setContentType(String)}. * </p> * * @author Justin Deoliveira, The Open Planning Project * */ public class LegacyServiceExceptionHandler extends ServiceExceptionHandler { /** * the version of the service exceptoin report. */ protected String version = "1.2.0"; /** * Location of document type defintion for document */ protected String dtdLocation = null; /** * Location of schema for document. */ protected String schemaLocation = null; /** * The content type of the produced document */ protected String contentType = "text/xml"; /** * The central configuration, used to decide whether to dump a verbose stack trace, or not */ protected GeoServer geoServer; public LegacyServiceExceptionHandler(List services, GeoServer geoServer) { super(services); this.geoServer = geoServer; } public LegacyServiceExceptionHandler(Service service, GeoServer geoServer) { super(service); this.geoServer = geoServer; } public void setVersion(String version) { this.version = version; } public void setDTDLocation(String dtd) { this.dtdLocation = dtd; } public void setSchemaLocation(String schemaLocation) { this.schemaLocation = schemaLocation; } public void setContentType(String contentType) { this.contentType = contentType; } public void handleServiceException(ServiceException exception, Request request) { String tab = " "; StringBuffer sb = new StringBuffer(); //xml header TODO: should the encoding the server default? sb.append("<?xml version=\"1.0\""); sb.append(" encoding=\"UTF-8\""); if (dtdLocation != null) { sb.append(" standalone=\"no\""); } sb.append("?>"); // dtd location if (dtdLocation != null) { String fullDtdLocation = buildSchemaURL(baseURL(request.getHttpRequest()), dtdLocation); sb.append("<!DOCTYPE ServiceExceptionReport SYSTEM \"" + fullDtdLocation + "\"> "); } //root element sb.append("<ServiceExceptionReport version=\"" + version + "\" "); //xml schema location if ((schemaLocation != null) && (dtdLocation == null)) { String fullSchemaLocation = buildSchemaURL(baseURL(request.getHttpRequest()), schemaLocation); sb.append("xmlns=\"http://www.opengis.net/ogc\" "); sb.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "); sb.append("xsi:schemaLocation=\"http://www.opengis.net/ogc " + fullSchemaLocation + "\""); } sb.append(">"); //write out the service exception sb.append(tab + "<ServiceException"); //exception code if ((exception.getCode() != null) && !exception.getCode().equals("")) { sb.append(" code=\"" + ResponseUtils.encodeXML(exception.getCode()) + "\""); } //exception locator if ((exception.getLocator() != null) && !exception.getLocator().equals("")) { sb.append(" locator=\"" + ResponseUtils.encodeXML(exception.getLocator()) + "\""); } sb.append(">"); //message if ((exception.getMessage() != null)) { sb.append("\n" + tab + tab); OwsUtils.dumpExceptionMessages(exception, sb, true); if(geoServer.getSettings().isVerboseExceptions()) { ByteArrayOutputStream stackTrace = new ByteArrayOutputStream(); exception.printStackTrace(new PrintStream(stackTrace)); sb.append("\nDetails:\n"); sb.append(ResponseUtils.encodeXML(new String(stackTrace.toByteArray()))); } } sb.append("\n</ServiceException>"); sb.append("</ServiceExceptionReport>"); HttpServletResponse response = request.getHttpResponse(); response.setContentType(contentType); //TODO: server encoding? response.setCharacterEncoding("UTF-8"); try { response.getOutputStream().write(sb.toString().getBytes()); response.getOutputStream().flush(); } catch (IOException e) { //throw new RuntimeException(e); // Hmm, not much we can do here. I guess log the fact that we couldn't write out the exception and be done with it... LOGGER.log(Level.INFO, "Problem writing exception information back to calling client:", e); } } }