/* (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.wcs2_0.exception;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import javax.servlet.http.HttpServletResponse;
import net.opengis.ows20.ExceptionType;
import net.opengis.ows20.ExceptionReportType;
import net.opengis.ows20.Ows20Factory;
import org.geoserver.ows.Request;
import org.geoserver.ows.ServiceExceptionHandler;
import org.geoserver.ows.util.OwsUtils;
import org.geoserver.platform.OWS20Exception;
import org.geoserver.platform.OWS20Exception.OWSExceptionCode;
import org.geoserver.platform.Service;
import org.geoserver.platform.ServiceException;
import org.geotools.ows.v2_0.OWS;
import org.geotools.ows.v2_0.OWSConfiguration;
import org.geotools.xml.Encoder;
/**
* A default implementation of {@link ServiceExceptionHandler} which outputs
* as service exception in a <code>ows:ExceptionReport</code> document.
* <p>
* This service exception handler will generate an OWS exception report,
* see {@linkplain "http://schemas.opengis.net/ows/1.1.0/owsExceptionReport.xsd"}.
* </p>
*
* @author Justin Deoliveira, The Open Planning Project
*
*/
public class OWS20ServiceExceptionHandler extends ServiceExceptionHandler {
/**
* A flag controlling whether the http return code should always be 200.
* It is required when running CITE tests for WCS2.0, but breaks OWS2 and WCS2 standards.
*/
public static boolean force200httpcode = Boolean.getBoolean("force200");
/**
* verbose exception flag controlling whether the exception stack trace will be included in the
* encoded ows exception report
*/
protected boolean verboseExceptions = false;
/**
* flag that controls what version to use in the ows exception report.
*/
protected boolean useServiceVersion = false;
/**
* Constructor to be called if the exception is not for a particular service.
*
*/
public OWS20ServiceExceptionHandler() {
super(Collections.EMPTY_LIST);
}
/**
* Constructor to be called if the exception is for a particular service.
*
* @param services List of services this handler handles exceptions for.
*/
public OWS20ServiceExceptionHandler(List services) {
super(services);
}
/**
* Constructor to be called if the exception is for a particular service.
*
* @param services List of services this handler handles exceptions for.
*/
public OWS20ServiceExceptionHandler(Service service) {
super(Arrays.asList(service));
}
/**
* Writes out an OWS ExceptionReport document.
*/
public void handleServiceException(ServiceException exception, Request request) {
LOGGER.warning("OWS20SEH: handling " + exception);
String version = null;
if (useServiceVersion && request.getServiceDescriptor() != null) {
version = request.getServiceDescriptor().getVersion().toString();
}
ExceptionReportType report = exceptionReport( exception, verboseExceptions, version );
HttpServletResponse response = request.getHttpResponse();
if (!request.isSOAP()) {
//there will already be a SOAP mime type
response.setContentType("application/xml");
}
OWS20Exception ows2ex;
if(exception instanceof OWS20Exception) {
ows2ex = (OWS20Exception)exception;
} else if ( exception.getCause() != null && exception.getCause() instanceof OWS20Exception) {
ows2ex = (OWS20Exception)exception.getCause();
} else {
// try to infer if it's a standard exception
String code = exception.getCode();
OWSExceptionCode exCode = OWS20Exception.OWSExceptionCode.getByCode(code);
if(exCode != null) {
ows2ex = new OWS20Exception(exception.getMessage(), exception, exCode, exception.getLocator());
} else {
ows2ex = new OWS20Exception(exception.getMessage(), exception, OWSExceptionCode.NoApplicableCode, exception.getLocator());
}
}
//response.setCharacterEncoding( "UTF-8" );
OWSConfiguration configuration = new OWSConfiguration();
Encoder encoder = new Encoder(configuration, configuration.schema());
encoder.setIndenting(true);
encoder.setIndentSize(2);
encoder.setLineWidth(60);
encoder.setOmitXMLDeclaration(request.isSOAP());
// String schemaLocation = buildSchemaURL(baseURL(request.getHttpRequest()), "ows/2.0/owsAll.xsd");
String schemaLocation = "http://schemas.opengis.net/ows/2.0/owsExceptionReport.xsd";
encoder.setSchemaLocation(OWS.NAMESPACE, schemaLocation);
try {
// if(ows2ex != null) {
if(ows2ex.getHttpCode() != null) {
response.setStatus(ows2ex.getHttpCode());
}
if(force200httpcode) {
response.setStatus(200);
}
encoder.encode(report, OWS.ExceptionReport, response.getOutputStream());
// }
} catch (Exception ex) {
//throw new RuntimeException(ex);
// 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:", ex);
} finally {
try {
response.getOutputStream().flush();
} catch (IOException ioe) {
}
}
}
/**
* Flag that controls what version to use in the ows exception report.
* <p>
* Setting to true will cause the service version to be used rather than the ows spec version.
* </p>
*/
public void setUseServiceVersion(boolean useServiceVersion) {
this.useServiceVersion = useServiceVersion;
}
public static ExceptionReportType exceptionReport(ServiceException exception,
boolean verboseExceptions, String version) {
ExceptionType e = Ows20Factory.eINSTANCE.createExceptionType();
if (exception.getCode() != null) {
e.setExceptionCode(exception.getCode());
} else {
//set a default
e.setExceptionCode("NoApplicableCode");
}
e.setLocator(exception.getLocator());
//add the message
StringBuffer sb = new StringBuffer();
OwsUtils.dumpExceptionMessages(exception, sb, true);
sb.append("\n");
sb.append(exception.getExceptionText()); // check this
// e.getExceptionText().add(sb.toString());
// e.getExceptionText().addAll(exception.getExceptionText());
if(verboseExceptions) {
//add the entire stack trace
//exception.
sb.append("\nDetails:\n");
ByteArrayOutputStream trace = new ByteArrayOutputStream();
exception.printStackTrace(new PrintStream(trace));
sb.append(new String(trace.toByteArray()));
}
e.setExceptionText(sb.toString());
ExceptionReportType report = Ows20Factory.eINSTANCE.createExceptionReportType();
version = version != null ? version : "2.0.0";
report.setVersion(version);
report.getException().add(e);
return report;
}
}