Java tutorial
/* * Copyright 2009-2016 DigitalGlobe, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and limitations under the License. * */ package org.mrgeo.resources.wms; import org.apache.commons.lang3.StringUtils; import org.mrgeo.colorscale.ColorScale; import org.mrgeo.colorscale.ColorScale.ColorScaleException; import org.mrgeo.colorscale.ColorScaleManager; import org.mrgeo.colorscale.applier.ColorScaleApplier; import org.mrgeo.data.DataProviderFactory; import org.mrgeo.data.ProviderProperties; import org.mrgeo.data.image.MrsImageDataProvider; import org.mrgeo.image.MrsImage; import org.mrgeo.image.MrsPyramid; import org.mrgeo.services.SecurityUtils; import org.mrgeo.services.Version; import org.mrgeo.services.mrspyramid.rendering.ImageHandlerFactory; import org.mrgeo.services.mrspyramid.rendering.ImageRenderer; import org.mrgeo.services.mrspyramid.rendering.ImageResponseWriter; import org.mrgeo.services.mrspyramid.rendering.TiffImageRenderer; import org.mrgeo.services.utils.DocumentUtils; import org.mrgeo.services.utils.RequestUtils; import org.mrgeo.utils.LatLng; import org.mrgeo.utils.tms.Bounds; import org.mrgeo.utils.tms.TMSUtils; import org.mrgeo.utils.XmlUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.CDATASection; import org.w3c.dom.Document; import org.w3c.dom.Element; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.core.*; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import java.awt.image.Raster; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Set; //import javax.servlet.http.HttpServlet; //import javax.servlet.http.HttpServletRequest; //import javax.servlet.http.HttpServletResponse; //import org.mrgeo.utils.LoggingUtils; /** * OGC WMS implementation - See https://107.23.31.196/redmine/projects/mrgeo/wiki/WmsReference for * details. */ @Path("/wms") public class WmsGenerator { private static final Logger log = LoggerFactory.getLogger(WmsGenerator.class); // private static Path basePath = null; // private static Path colorScaleBasePath = null; // private static CoordinateReferenceSystem coordSys = null; public static final String JPEG_MIME_TYPE = "image/jpeg"; public static final String PNG_MIME_TYPE = "image/png"; public static final String TIFF_MIME_TYPE = "image/tiff"; private Version version = new Version(WMS_VERSION); public static final String WMS_VERSION = "1.3.0"; private static final String WMS_SERVICE = "wms"; public WmsGenerator() { } /** * Calculates the scale of the requested WMS layer * * @param image * source data * @return scale resolution */ public static double calculateScale(final MrsImage image) { // WMS defines a pixel as .28mm final double h = TMSUtils.resolution(image.getZoomlevel(), image.getTilesize()) * LatLng.METERS_PER_DEGREE; return h / 2.8e-4; } /** * Returns the value for the specified paramName case-insensitively. If the * parameter does not exist, it returns null. * */ private String getQueryParam(MultivaluedMap<String, String> allParams, String paramName) { for (String key : allParams.keySet()) { if (key.equalsIgnoreCase(paramName)) { List<String> value = allParams.get(key); if (value.size() == 1) { return value.get(0); } } } return null; } /** * Returns the value for the specified paramName case-insensitively. If the * parameter does not exist, it returns defaultValue. * */ private String getQueryParam(MultivaluedMap<String, String> allParams, String paramName, String defaultValue) { String value = getQueryParam(allParams, paramName); if (value != null) { return value; } return defaultValue; } private boolean paramExists(MultivaluedMap<String, String> allParams, String paramName) { for (String key : allParams.keySet()) { if (key.equalsIgnoreCase(paramName)) { List<String> value = allParams.get(key); return (value.size() > 0); } } return false; } private String getActualQueryParamName(MultivaluedMap<String, String> allParams, String paramName) { for (String key : allParams.keySet()) { if (key.equalsIgnoreCase(paramName)) { return key; } } return null; } /** * Returns the int value for the specified paramName case-insensitively. If * the parameter value exists, but is not an int, it throws a NumberFormatException. * If it does not exist, it returns defaultValue. * */ private int getQueryParamAsInt(MultivaluedMap<String, String> allParams, String paramName, int defaultValue) throws NumberFormatException { for (String key : allParams.keySet()) { if (key.equalsIgnoreCase(paramName)) { List<String> value = allParams.get(key); if (value.size() == 1) { return Integer.parseInt(value.get(0)); } } } return defaultValue; } /** * Returns the int value for the specified paramName case-insensitively. If * the parameter value exists, but is not an int, it throws a NumberFormatException. * If it does not exist, it returns defaultValue. * */ private double getQueryParamAsDouble(MultivaluedMap<String, String> allParams, String paramName, double defaultValue) throws NumberFormatException { for (String key : allParams.keySet()) { if (key.equalsIgnoreCase(paramName)) { List<String> value = allParams.get(key); if (value.size() == 1) { return Double.parseDouble(value.get(0)); } } } return defaultValue; } @GET public Response doGet(@Context UriInfo uriInfo) { return handleRequest(uriInfo); } @POST public Response doPost(@Context UriInfo uriInfo) { return handleRequest(uriInfo); } private Response handleRequest(@Context UriInfo uriInfo) { long start = System.currentTimeMillis(); try { MultivaluedMap<String, String> allParams = uriInfo.getQueryParameters(); String request = getQueryParam(allParams, "request", "GetCapabilities"); ProviderProperties providerProperties = SecurityUtils.getProviderProperties(); String serviceName = getQueryParam(allParams, "service"); if (serviceName == null) { return writeError(Response.Status.BAD_REQUEST, "Missing required SERVICE parameter. Should be set to \"WMS\""); } if (!serviceName.equalsIgnoreCase("wms")) { return writeError(Response.Status.BAD_REQUEST, "Invalid SERVICE parameter. Should be set to \"WMS\""); } if (request.equalsIgnoreCase("getmap")) { return getMap(allParams, providerProperties); } else if (request.equalsIgnoreCase("getmosaic")) { return getMosaic(allParams, providerProperties); } else if (request.equalsIgnoreCase("gettile")) { return getTile(allParams, providerProperties); } else if (request.equalsIgnoreCase("getcapabilities")) { return getCapabilities(uriInfo, allParams, providerProperties); } else if (request.equalsIgnoreCase("describetiles")) { return describeTiles(uriInfo, allParams, providerProperties); } return writeError(Response.Status.BAD_REQUEST, "Invalid request"); } finally { if (log.isDebugEnabled()) { log.debug("WMS request time: {}ms", (System.currentTimeMillis() - start)); // this can be resource intensive. System.gc(); final Runtime rt = Runtime.getRuntime(); log.debug(String.format("WMS request memory: %.1fMB / %.1fMB\n", (rt.totalMemory() - rt.freeMemory()) / 1e6, rt.maxMemory() / 1e6)); } } } private boolean isCacheOff(MultivaluedMap<String, String> allParams) { String cacheValue = getQueryParam(allParams, "cache", ""); return (!StringUtils.isEmpty(cacheValue) && cacheValue.equalsIgnoreCase("off")); } private Response.ResponseBuilder setupCaching(Response.ResponseBuilder builder, MultivaluedMap<String, String> allParams) { boolean cacheOff = isCacheOff(allParams); CacheControl cacheControl = new CacheControl(); if (cacheOff) { cacheControl.setNoStore(true); cacheControl.setNoCache(true); // This is retained from the original WmsGenerator, but it seems wrong. return builder.cacheControl(cacheControl).expires(new Date(0)); } else { // This is retained from the original WmsGenerator, but it seems wrong. cacheControl.setMaxAge(3600); cacheControl.setNoCache(false); return builder.cacheControl(cacheControl).expires(new Date(3600)); } } private Response getMap(MultivaluedMap<String, String> allParams, ProviderProperties providerProperties) { // Get all of the query parameter values needed and validate them String layers = getQueryParam(allParams, "layers"); String[] layerNames = null; if (layers != null && !layers.isEmpty()) { layerNames = layers.split(","); } if (layerNames == null || layerNames.length == 0) { return writeError(Response.Status.BAD_REQUEST, "Missing required LAYERS parameter"); } if (layerNames.length > 1) { return writeError(Response.Status.BAD_REQUEST, "Only one LAYER is supported"); } String styles = getQueryParam(allParams, "styles"); String styleNames[] = null; if (styles != null && !styles.isEmpty()) { styleNames = styles.split(","); // if (styleNames.length != layerNames.length) // { // return writeError(Response.Status.BAD_REQUEST, "There are a different number of LAYERS (" + layerNames.length + ") than STYLES(" + styleNames.length + ")"); // } } // else // { // return writeError(Response.Status.BAD_REQUEST, "Missing required STYLES parameter"); // } String srs; try { srs = getSrsParam(allParams); } catch (Exception e) { return writeError(Response.Status.BAD_REQUEST, e.getMessage()); } Bounds bounds; try { bounds = getBoundsParam(allParams, "bbox"); } catch (Exception e) { return writeError(Response.Status.BAD_REQUEST, e.getMessage()); } String format = getQueryParam(allParams, "format"); if (format == null) { return writeError(Response.Status.BAD_REQUEST, "Missing required FORMAT parameter"); } if (!paramExists(allParams, "width")) { return writeError(Response.Status.BAD_REQUEST, "Missing required WIDTH parameter"); } int width = getQueryParamAsInt(allParams, "width", 0); if (!paramExists(allParams, "height")) { return writeError(Response.Status.BAD_REQUEST, "Missing required HEIGHT parameter"); } int height = getQueryParamAsInt(allParams, "height", 0); ImageRenderer renderer; try { renderer = (ImageRenderer) ImageHandlerFactory.getHandler(format, ImageRenderer.class); } catch (Exception e) { return writeError(Response.Status.BAD_REQUEST, e.getMessage()); } // Reproject bounds to EPSG:4326 if necessary try { bounds = RequestUtils.reprojectBounds(bounds, srs); } catch (Exception e) { return writeError(Response.Status.BAD_REQUEST, e.getMessage()); } // Return the resulting image try { Raster result = renderer.renderImage(layerNames[0], bounds, width, height, providerProperties, srs); result = colorRaster(layerNames[0], (styleNames != null && styleNames.length > 0) ? styleNames[0] : null, format, renderer, result); Response.ResponseBuilder builder = ((ImageResponseWriter) ImageHandlerFactory.getHandler(format, ImageResponseWriter.class)).write(result, layerNames[0], bounds); return setupCaching(builder, allParams).build(); } catch (Exception e) { log.error("Unable to render the image in getTile", e); return writeError(Response.Status.BAD_REQUEST, e.getMessage()); } } /** * Gets the value for the paramName from allParams. If the value does not exist, it * throws an exception. It then parses the minX, minY, maxX and maxY settings from * the value. If any of the settings are not valid or missing, it throws an * exception. If all validation passes, it returns a Bounds object configured with * those settings. * * @throws Exception */ private Bounds getBoundsParam(MultivaluedMap<String, String> allParams, String paramName) throws Exception { String bbox = getQueryParam(allParams, paramName); if (bbox == null) { throw new Exception("Missing required BBOX parameter"); } String[] bboxComponents = bbox.split(","); if (bboxComponents.length != 4) { throw new Exception("Invalid BBOX parameter. Should contain minX, minY, maxX, maxY"); } double[] bboxValues = new double[4]; for (int index = 0; index < bboxComponents.length; index++) { try { bboxValues[index] = Double.parseDouble(bboxComponents[index]); } catch (NumberFormatException nfe) { throw new Exception("Invalid BBOX value: " + bboxComponents[index]); } } return new Bounds(bboxValues[0], bboxValues[1], bboxValues[2], bboxValues[3]); } private String getSrsParam(MultivaluedMap<String, String> allParams) throws Exception { String srs = getQueryParam(allParams, "srs"); if (srs == null || srs.isEmpty()) { String crs = getQueryParam(allParams, "crs"); if (crs == null || crs.isEmpty()) { return null; } else { return crs; } } else { return srs; } } /* * GetMosaic implementation */ private Response getMosaic(MultivaluedMap<String, String> allParams, ProviderProperties providerProperties) { String layers = getQueryParam(allParams, "layers"); String[] layerNames = null; if (layers != null && !layers.isEmpty()) { layerNames = layers.split(","); } if (layerNames == null || layerNames.length == 0) { return writeError(Response.Status.BAD_REQUEST, "Missing required LAYERS parameter"); } if (layerNames.length > 1) { return writeError(Response.Status.BAD_REQUEST, "Only one LAYER is supported"); } final Bounds bounds; try { bounds = getBoundsParam(allParams, "bbox"); } catch (Exception e) { return writeError(Response.Status.BAD_REQUEST, e.getMessage()); } String styles = getQueryParam(allParams, "styles"); String styleNames[] = null; if (styles != null && !styles.isEmpty()) { styleNames = styles.split(","); // if (styleNames.length != layerNames.length) // { // return writeError(Response.Status.BAD_REQUEST, "There are a different number of LAYERS (" + layerNames.length + ") than STYLES(" + styleNames.length + ")"); // } } // else // { // return writeError(Response.Status.BAD_REQUEST, "Missing required STYLES parameter"); // } final String srs; try { srs = getSrsParam(allParams); } catch (Exception e) { return writeError(Response.Status.BAD_REQUEST, e.getMessage()); } String format = getQueryParam(allParams, "format"); if (format == null) { return writeError(Response.Status.BAD_REQUEST, "Missing required FORMAT parameter"); } ImageRenderer renderer; try { renderer = (ImageRenderer) ImageHandlerFactory.getHandler(format, ImageRenderer.class); } catch (Exception e) { return writeError(Response.Status.BAD_REQUEST, e.getMessage()); } try { Raster result = renderer.renderImage(layerNames[0], bounds, providerProperties, srs); result = colorRaster(layerNames[0], (styleNames != null && styleNames.length > 0) ? styleNames[0] : null, format, renderer, result); Response.ResponseBuilder builder = ((ImageResponseWriter) ImageHandlerFactory.getHandler(format, ImageResponseWriter.class)).write(result, layerNames[0], bounds); return setupCaching(builder, allParams).build(); } catch (Exception e) { log.error("Unable to render the image in getMosaic", e); return writeError(Response.Status.BAD_REQUEST, e.getMessage()); } } private static ColorScale getDefaultColorScale() { ColorScale cs = null; try { cs = ColorScaleManager.fromName("Default"); } catch (ColorScaleException e) { // Do nothing - there may not be a Default color scale defined } if (cs == null) { cs = ColorScale.createDefault(); } return cs; } /* * Returns a list of all MrsPyramid version 2 data in the home data directory */ private static MrsImageDataProvider[] getPyramidFilesList(final ProviderProperties providerProperties) throws IOException { String[] images = DataProviderFactory.listImages(providerProperties); Arrays.sort(images); MrsImageDataProvider[] providers = new MrsImageDataProvider[images.length]; for (int i = 0; i < images.length; i++) { providers[i] = DataProviderFactory.getMrsImageDataProvider(images[i], DataProviderFactory.AccessMode.READ, providerProperties); } return providers; // Path basePath = new Path(HadoopUtils.getDefaultImageBaseDirectory()); // final FileSystem fileSystem = HadoopFileUtils.getFileSystem(basePath); // // log.debug(HadoopFileUtils.getDefaultRoot().toString()); // // log.debug("basePath: {}", fileSystem.makeQualified(basePath).toString()); // FileStatus[] allFiles = fileSystem.listStatus(basePath); // if (allFiles == null || allFiles.length == 0) // { // log.warn("Base path either doesn't exist or has no files. {}", basePath.toString()); // allFiles = new FileStatus[0]; // } // // final LinkedList<FileStatus> files = new LinkedList<FileStatus>(); // for (final FileStatus f : allFiles) // { // if (f.isDir()) // { // final Path metadataPath = new Path(f.getPath(), "metadata"); // if (fileSystem.exists(metadataPath)) // { // log.debug("Using directory: {}", f.getPath().toString()); // files.add(f); // } // else // { // log.warn("Skipping directory: {}", f.getPath().toString()); // } // } // else // { // log.debug("Skipping file: {}", f.getPath().toString()); // } // } // return files; } /* * GetTile implementation */ private Response getTile(MultivaluedMap<String, String> allParams, final ProviderProperties providerProperties) { String versionStr = getQueryParam(allParams, "version", "1.4.0"); version = new Version(versionStr); if (version.isLess("1.4.0")) { return writeError(Response.Status.BAD_REQUEST, "Get tile is only supported with version >= 1.4.0"); } String layer = getQueryParam(allParams, "layer"); if (layer == null || layer.isEmpty()) { return writeError(Response.Status.BAD_REQUEST, "Missing required LAYER parameter"); } String style = getQueryParam(allParams, "style"); // if (style == null || style.isEmpty()) // { // return writeError(Response.Status.BAD_REQUEST, "Missing required STYLE parameter"); // } String format = getQueryParam(allParams, "format"); if (format == null) { return writeError(Response.Status.BAD_REQUEST, "Missing required FORMAT parameter"); } int tileRow; if (paramExists(allParams, "tilerow")) { tileRow = getQueryParamAsInt(allParams, "tilerow", -1); } else { return writeError(Response.Status.BAD_REQUEST, "Missing required TILEROW parameter"); } int tileCol; if (paramExists(allParams, "tilecol")) { tileCol = getQueryParamAsInt(allParams, "tilecol", -1); } else { return writeError(Response.Status.BAD_REQUEST, "Missing required TILECOL parameter"); } double scale; if (paramExists(allParams, "scale")) { scale = getQueryParamAsDouble(allParams, "scale", 0.0); } else { return writeError(Response.Status.BAD_REQUEST, "Missing required SCALE parameter"); } final ImageRenderer renderer; try { renderer = (ImageRenderer) ImageHandlerFactory.getHandler(format, ImageRenderer.class); } catch (Exception e) { return writeError(Response.Status.BAD_REQUEST, e.getMessage()); } try { Raster result = renderer.renderImage(layer, tileCol, tileRow, scale, providerProperties); result = colorRaster(layer, style, format, renderer, result); Response.ResponseBuilder builder = ((ImageResponseWriter) ImageHandlerFactory.getHandler(format, ImageResponseWriter.class)).write(result, tileCol, tileRow, scale, MrsPyramid.open(layer, providerProperties)); return setupCaching(builder, allParams).build(); } catch (Exception e) { log.error("Unable to render the image in getTile", e); return writeError(Response.Status.BAD_REQUEST, e.getMessage()); } } private static Raster colorRaster(String layer, String style, String imageFormat, ImageRenderer renderer, Raster result) throws Exception { if (!(renderer instanceof TiffImageRenderer)) { log.debug("Applying color scale to image {} ...", layer); ColorScale cs; if (style != null && !style.equalsIgnoreCase("default")) { cs = ColorScaleManager.fromName(style); if (cs == null) { throw new IOException("Can not load style: " + style); } } else { cs = ColorScale.createDefaultGrayScale(); } result = ((ColorScaleApplier) ImageHandlerFactory.getHandler(imageFormat, ColorScaleApplier.class)) .applyColorScale(result, cs, renderer.getExtrema(), renderer.getDefaultValues()); log.debug("Color scale applied to image {}", layer); } return result; } /* * DescribeTiles implementation */ private Response describeTiles(UriInfo uriInfo, MultivaluedMap<String, String> allParams, final ProviderProperties providerProperties) { String versionStr = getQueryParam(allParams, "version", "1.4.0"); version = new Version(versionStr); if (version.isLess("1.4.0")) { return writeError(Response.Status.BAD_REQUEST, "Describe tiles is only supported with version >= 1.4.0"); } try { final DescribeTilesDocumentGenerator docGen = new DescribeTilesDocumentGenerator(); final Document doc = docGen.generateDoc(version, uriInfo.getRequestUri().toString(), getPyramidFilesList(providerProperties)); ByteArrayOutputStream xmlStream = new ByteArrayOutputStream(); final PrintWriter out = new PrintWriter(xmlStream); // DocumentUtils.checkForErrors(doc); DocumentUtils.writeDocument(doc, version, WMS_SERVICE, out); out.close(); return Response.ok(xmlStream.toString()).type(MediaType.APPLICATION_XML).build(); } catch (Exception e) { return writeError(Response.Status.BAD_REQUEST, e.getMessage()); } } /* * GetCapabilities implementation */ private Response getCapabilities(UriInfo uriInfo, MultivaluedMap<String, String> allParams, ProviderProperties providerProperties) { // The versionParamName will be null if the request did not include the // version parameter. String versionParamName = getActualQueryParamName(allParams, "version"); String versionStr = getQueryParam(allParams, "version", "1.1.1"); Version version = new Version(versionStr); // conform to the version negotiation standards of WMS. if (version.isLess("1.3.0")) { versionStr = "1.1.1"; version = new Version(versionStr); } else if (version.isLess("1.4.0")) { versionStr = "1.3.0"; version = new Version(versionStr); } else { versionStr = "1.4.0"; version = new Version(versionStr); } final GetCapabilitiesDocumentGenerator docGen = new GetCapabilitiesDocumentGenerator(); try { // The following code re-builds the request URI to include in the GetCapabilities // output. It sorts the parameters so that they are included in the URI in a // predictable order. The reason for this is so that test cases can compare XML // golden files against the XML generated here without worrying about parameters // shifting locations in the URI. Set<String> keys = uriInfo.getQueryParameters().keySet(); String[] sortedKeys = new String[keys.size()]; keys.toArray(sortedKeys); Arrays.sort(sortedKeys); UriBuilder builder = uriInfo.getBaseUriBuilder().path(uriInfo.getPath()); for (String key : sortedKeys) { // Only include the VERSION parameter in the URI used in GetCapabilities // if it was included in the original URI request. if (key.equalsIgnoreCase("version")) { if (versionParamName != null) { builder = builder.queryParam(versionParamName, versionStr); } } else { builder = builder.queryParam(key, getQueryParam(allParams, key)); } } final Document doc = docGen.generateDoc(version, builder.build().toString(), getPyramidFilesList(providerProperties)); ByteArrayOutputStream xmlStream = new ByteArrayOutputStream(); final PrintWriter out = new PrintWriter(xmlStream); // DocumentUtils.checkForErrors(doc); DocumentUtils.writeDocument(doc, version, WMS_SERVICE, out); out.close(); return Response.ok(xmlStream.toString()).type(MediaType.APPLICATION_XML).build(); } catch (Exception e) { return writeError(Response.Status.BAD_REQUEST, e.getMessage()); } } /* * Writes OGC spec error messages to the response */ private Response writeError(Response.Status httpStatus, final Exception e) { try { Document doc; final DocumentBuilderFactory dBF = DocumentBuilderFactory.newInstance(); final DocumentBuilder builder; builder = dBF.newDocumentBuilder(); doc = builder.newDocument(); final Element ser = doc.createElement("ServiceExceptionReport"); doc.appendChild(ser); ser.setAttribute("version", WMS_VERSION); final Element se = XmlUtils.createElement(ser, "ServiceException"); String msg = e.getLocalizedMessage(); if (msg == null || msg.isEmpty()) { msg = e.getClass().getName(); } final ByteArrayOutputStream strm = new ByteArrayOutputStream(); e.printStackTrace(new PrintStream(strm)); CDATASection msgNode = doc.createCDATASection(strm.toString()); se.appendChild(msgNode); final ByteArrayOutputStream xmlStream = new ByteArrayOutputStream(); final PrintWriter out = new PrintWriter(xmlStream); DocumentUtils.writeDocument(doc, version, WMS_SERVICE, out); out.close(); return Response.status(httpStatus).header("Content-Type", MediaType.TEXT_XML) .entity(xmlStream.toString()).build(); } catch (ParserConfigurationException e1) { } catch (TransformerException e1) { } // Fallback in case there is an XML exception above return Response.status(httpStatus).entity(e.getLocalizedMessage()).build(); } /* * Writes OGC spec error messages to the response */ private Response writeError(Response.Status httpStatus, final String msg) { try { Document doc; final DocumentBuilderFactory dBF = DocumentBuilderFactory.newInstance(); final DocumentBuilder builder = dBF.newDocumentBuilder(); doc = builder.newDocument(); final Element ser = doc.createElement("ServiceExceptionReport"); doc.appendChild(ser); ser.setAttribute("version", WMS_VERSION); final Element se = XmlUtils.createElement(ser, "ServiceException"); CDATASection msgNode = doc.createCDATASection(msg); se.appendChild(msgNode); final ByteArrayOutputStream xmlStream = new ByteArrayOutputStream(); final PrintWriter out = new PrintWriter(xmlStream); DocumentUtils.writeDocument(doc, version, WMS_SERVICE, out); out.close(); return Response.status(httpStatus).header("Content-Type", MediaType.TEXT_XML) .entity(xmlStream.toString()).build(); } catch (ParserConfigurationException e1) { } catch (TransformerException e1) { } // Fallback in case there is an XML exception above return Response.status(httpStatus).entity(msg).build(); } /* * Writes OGC spec error messages to the response */ private Response writeError(Response.Status httpStatus, final String code, final String msg) { try { Document doc; final DocumentBuilderFactory dBF = DocumentBuilderFactory.newInstance(); final DocumentBuilder builder = dBF.newDocumentBuilder(); doc = builder.newDocument(); final Element ser = doc.createElement("ServiceExceptionReport"); doc.appendChild(ser); ser.setAttribute("version", WMS_VERSION); final Element se = XmlUtils.createElement(ser, "ServiceException"); se.setAttribute("code", code); CDATASection msgNode = doc.createCDATASection(msg); se.appendChild(msgNode); final ByteArrayOutputStream xmlStream = new ByteArrayOutputStream(); final PrintWriter out = new PrintWriter(xmlStream); DocumentUtils.writeDocument(doc, version, WMS_SERVICE, out); out.close(); return Response.status(httpStatus).header("Content-Type", MediaType.TEXT_XML) .entity(xmlStream.toString()).build(); } catch (ParserConfigurationException e1) { } catch (TransformerException e1) { } // Fallback in case there is an XML exception above return Response.status(httpStatus).entity(msg).build(); } }