001: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
002: * This code is licensed under the GPL 2.0 license, availible at the root
003: * application directory.
004: */
005: package org.vfny.geoserver.wcs.responses;
006:
007: import org.geotools.factory.Hints;
008: import org.geotools.geometry.GeneralEnvelope;
009: import org.geotools.referencing.ReferencingFactoryFinder;
010: import org.opengis.coverage.grid.GridGeometry;
011: import org.opengis.referencing.crs.CRSAuthorityFactory;
012: import org.opengis.referencing.crs.CRSFactory;
013: import org.opengis.referencing.datum.DatumFactory;
014: import org.opengis.referencing.operation.CoordinateOperationFactory;
015: import org.opengis.referencing.operation.MathTransform;
016: import org.opengis.referencing.operation.MathTransformFactory;
017: import org.opengis.util.InternationalString;
018: import org.vfny.geoserver.Request;
019: import org.vfny.geoserver.Response;
020: import org.vfny.geoserver.global.CoverageDimension;
021: import org.vfny.geoserver.global.CoverageInfo;
022: import org.vfny.geoserver.global.GeoServer;
023: import org.vfny.geoserver.global.Service;
024: import org.vfny.geoserver.global.WCS;
025: import org.vfny.geoserver.wcs.WcsException;
026: import org.vfny.geoserver.wcs.requests.DescribeRequest;
027: import org.vfny.geoserver.wcs.requests.WCSRequest;
028:
029: import java.awt.geom.AffineTransform;
030: import java.io.IOException;
031: import java.io.OutputStream;
032: import java.util.ArrayList;
033: import java.util.HashMap;
034: import java.util.List;
035: import java.util.TreeSet;
036: import java.util.logging.Logger;
037:
038: /**
039: * DOCUMENT ME!
040: *
041: * @author $Author: Alessio Fabiani (alessio.fabiani@gmail.com) $ (last
042: * modification)
043: * @author $Author: Simone Giannecchini (simboss1@gmail.com) $ (last
044: * modification)
045: */
046: public class DescribeResponse implements Response {
047: private static final Logger LOGGER = org.geotools.util.logging.Logging
048: .getLogger("org.vfny.geoserver.responses");
049: private static final String CURR_VER = "\"1.0.0\"";
050: private static final String WCS_URL = "http://www.opengis.net/wcs";
051: private static final String WCS_NAMESPACE = new StringBuffer(
052: "\n xmlns=\"").append(WCS_URL).append("\"").toString();
053: private static final String XLINK_URL = "\"http://www.w3.org/1999/xlink\"";
054: private static final String XLINK_NAMESPACE = new StringBuffer(
055: "\n xmlns:xlink=").append(XLINK_URL).toString();
056: private static final String OGC_URL = "\"http://www.opengis.net/ogc\"";
057: private static final String OGC_NAMESPACE = new StringBuffer(
058: "\n xmlns:ogc=").append(OGC_URL).toString();
059: private static final String GML_URL = "\"http://www.opengis.net/gml\"";
060: private static final String GML_NAMESPACE = new StringBuffer(
061: "\n xmlns:gml=").append(GML_URL).toString();
062: private static final String SCHEMA_URI = "\"http://www.w3.org/2001/XMLSchema-instance\"";
063: private static final String XSI_NAMESPACE = new StringBuffer(
064: "\n xmlns:xsi=").append(SCHEMA_URI).toString();
065:
066: /** Fixed return footer information */
067: private static final String FOOTER = "\n</CoverageDescription>";
068:
069: /**
070: *
071: * @uml.property name="request"
072: * @uml.associationEnd multiplicity="(0 1)"
073: */
074: private DescribeRequest request;
075:
076: /** Main XML class for interpretation and response. */
077: private String xmlResponse = new String();
078:
079: /**
080: * The default datum factory.
081: *
082: * @uml.property name="datumFactory"
083: * @uml.associationEnd multiplicity="(1 1)"
084: */
085: protected final DatumFactory datumFactory = ReferencingFactoryFinder
086: .getDatumFactory(null);
087:
088: /**
089: * Returns any extra headers that this service might want to set in the HTTP response object.
090: * @see org.vfny.geoserver.Response#getResponseHeaders()
091: */
092: public HashMap getResponseHeaders() {
093: return null;
094: }
095:
096: /**
097: * The default coordinate reference system factory.
098: */
099:
100: // protected final static CRSFactory crsFactory =
101: // FactoryFinder.getCRSFactory(new
102: // Hints(Hints.CRS_AUTHORITY_FACTORY,EPSGCRSAuthorityFactory.class));
103: protected final static CRSFactory crsFactory = ReferencingFactoryFinder
104: .getCRSFactory(new Hints(Hints.CRS_AUTHORITY_FACTORY,
105: CRSAuthorityFactory.class));
106:
107: /**
108: * The default math transform factory.
109: *
110: * @uml.property name="mtFactory"
111: * @uml.associationEnd multiplicity="(1 1)"
112: */
113: protected final MathTransformFactory mtFactory = ReferencingFactoryFinder
114: .getMathTransformFactory(null);
115:
116: /**
117: * The default transformations factory.
118: */
119: protected final static CoordinateOperationFactory opFactory = ReferencingFactoryFinder
120: .getCoordinateOperationFactory(new Hints(
121: Hints.LENIENT_DATUM_SHIFT, Boolean.TRUE));
122:
123: public void execute(Request req) throws WcsException {
124: WCSRequest request = (WCSRequest) req;
125:
126: if (!(request instanceof DescribeRequest)) {
127: throw new WcsException(
128: new StringBuffer(
129: "illegal request type, expected DescribeRequest, got ")
130: .append(request).toString());
131: }
132:
133: DescribeRequest wcsRequest = (DescribeRequest) request;
134: this .request = wcsRequest;
135: LOGGER.finer("processing describe request" + wcsRequest);
136:
137: String outputFormat = wcsRequest.getOutputFormat();
138:
139: if (!outputFormat.equalsIgnoreCase("XMLSCHEMA")) {
140: throw new WcsException(new StringBuffer("output format: ")
141: .append(outputFormat).append(" not ").append(
142: "supported by geoserver").toString());
143: }
144:
145: // generates response, using general function
146: xmlResponse = generateCoverages(wcsRequest);
147:
148: if (!request.getWCS().getGeoServer().isVerbose()) {
149: xmlResponse = xmlResponse.replaceAll(">\n[ \\t\\n]*", ">");
150: xmlResponse = xmlResponse.replaceAll("\n[ \\t\\n]*", " ");
151: }
152: }
153:
154: public String getContentType(GeoServer gs) {
155: return gs.getMimeType();
156: }
157:
158: public String getContentEncoding() {
159: return null;
160: }
161:
162: public String getContentDisposition() {
163: return null;
164: }
165:
166: public void writeTo(OutputStream out) throws WcsException {
167: try {
168: byte[] content = xmlResponse.getBytes();
169: out.write(content);
170: } catch (IOException ex) {
171: throw new WcsException(ex, "", getClass().getName());
172: }
173: }
174:
175: private final String generateCoverages(DescribeRequest wcsRequest)
176: throws WcsException {
177: List requestedTypes = wcsRequest.getCoverages();
178:
179: // Initialize return information and intermediate return objects
180: StringBuffer tempResponse = new StringBuffer();
181:
182: // ComplexType table = new ComplexType();
183: if (requestedTypes.size() == 0) {
184: // if there are no specific requested types then get all.
185: requestedTypes = new ArrayList(wcsRequest.getWCS()
186: .getData().getCoverageInfos().keySet());
187: }
188:
189: tempResponse.append("<?xml version=\"1.0\" encoding=\"")
190: .append(wcsRequest.getGeoServer().getCharSet().name())
191: .append("\"?>").append(
192: "\n<CoverageDescription version=").append(
193: CURR_VER).append(" ").toString();
194:
195: tempResponse.append(WCS_NAMESPACE);
196: tempResponse.append(XLINK_NAMESPACE);
197: tempResponse.append(OGC_NAMESPACE);
198: tempResponse.append(GML_NAMESPACE);
199: tempResponse.append(XSI_NAMESPACE);
200: /*tempResponse.append(" xsi:schemaLocation=\"").append(WCS_URL).append(
201: " ").append(request.getSchemaBaseUrl()).append(
202: "wcs/1.0.0/describeCoverage.xsd\">\n\n");*/
203: tempResponse.append(" xsi:schemaLocation=\"").append(WCS_URL)
204: .append(" ").append(
205: "http://schemas.opengis.net/wcs/1.0.0/")
206: .append("describeCoverage.xsd\">\n\n");
207:
208: tempResponse.append(generateSpecifiedCoverages(requestedTypes,
209: wcsRequest.getWCS()));
210:
211: tempResponse.append(FOOTER);
212:
213: return tempResponse.toString();
214: }
215:
216: private String generateSpecifiedCoverages(List requestedTypes,
217: WCS gs) throws WcsException {
218: String tempResponse = new String();
219: String curCoverageName = new String();
220:
221: final int length = requestedTypes.size();
222: CoverageInfo meta;
223:
224: for (int i = 0; i < length; i++) {
225: curCoverageName = requestedTypes.get(i).toString();
226:
227: meta = gs.getData().getCoverageInfo(curCoverageName);
228:
229: if (meta == null) {
230: throw new WcsException(new StringBuffer("Coverage ")
231: .append(curCoverageName).append(" does ")
232: .append("not exist on this server").toString());
233: }
234:
235: tempResponse = tempResponse + printElement(meta);
236: }
237:
238: tempResponse = tempResponse + "\n\n";
239:
240: return tempResponse;
241: }
242:
243: private static String printElement(CoverageInfo cv) {
244: StringBuffer tempResponse = new StringBuffer();
245:
246: tempResponse.append("\n <CoverageOffering>");
247:
248: if (cv.getMetadataLink() != null) {
249: tempResponse.append("\n <metadataLink about=\"").append(
250: cv.getMetadataLink().getAbout()).append(
251: "\" metadataType=\"").append(
252: cv.getMetadataLink().getMetadataType()).append(
253: "\"/>");
254: }
255:
256: String tmp = cv.getDescription();
257:
258: if ((tmp != null) && (tmp != "")) {
259: tempResponse.append("\n <description>").append(tmp)
260: .append("</description>");
261: }
262:
263: tmp = cv.getName();
264:
265: if ((tmp != null) && (tmp != "")) {
266: tempResponse.append("\n <name>").append(tmp).append(
267: "</name>");
268: }
269:
270: tmp = cv.getLabel();
271:
272: if ((tmp != null) && (tmp != "")) {
273: tempResponse.append("\n <label>").append(tmp).append(
274: "</label>");
275: }
276:
277: final GeneralEnvelope envelope = cv.getWGS84LonLatEnvelope();
278:
279: tempResponse.append(
280: "\n <lonLatEnvelope" + " srsName=\"WGS84(DD)\"") /*urn:ogc:def:crs:OGC:1.3:CRS84*/
281: .append(">");
282: tempResponse.append("\n <gml:pos>").append(
283: envelope.getLowerCorner().getOrdinate(0)).append(" ")
284: .append(envelope.getLowerCorner().getOrdinate(1))
285: .append("</gml:pos>");
286: tempResponse.append("\n <gml:pos>").append(
287: envelope.getUpperCorner().getOrdinate(0)).append(" ")
288: .append(envelope.getUpperCorner().getOrdinate(1))
289: .append("</gml:pos>");
290: /*tempResponse.append("\n <gml:timePosition></gml:timePosition>");
291: tempResponse.append("\n <gml:timePosition></gml:timePosition>");*/
292: tempResponse.append("\n </lonLatEnvelope>");
293:
294: if ((cv.getKeywords() != null) && (cv.getKeywords().size() > 0)) {
295: tempResponse.append("\n <keywords>");
296:
297: for (int i = 0; i < cv.getKeywords().size(); i++)
298: tempResponse.append("\n <keyword>"
299: + cv.getKeywords().get(i) + "</keyword>");
300:
301: tempResponse.append("\n </keywords>");
302: }
303:
304: // TODO we need to signal somehow that something went wrong
305: GeneralEnvelope cvEnvelope = cv.getEnvelope();
306: // try {
307: // cvEnvelope =
308: // CoverageStoreUtils.adjustEnvelopeLongitudeFirst(cv.getEnvelope()
309: // .getCoordinateReferenceSystem(), cv.getEnvelope());
310: // } catch (MismatchedDimensionException e) {
311: // LOGGER.logp(Level.SEVERE, DescribeResponse.class.toString(),
312: // "private static String printElement(CoverageInfo cv)", e
313: // .getLocalizedMessage(), e);
314: //
315: // } catch (IndexOutOfBoundsException e) {
316: // LOGGER.logp(Level.SEVERE, DescribeResponse.class.toString(),
317: // "private static String printElement(CoverageInfo cv)", e
318: // .getLocalizedMessage(), e);
319: // } catch (NoSuchAuthorityCodeException e) {
320: // LOGGER.logp(Level.SEVERE, DescribeResponse.class.toString(),
321: // "private static String printElement(CoverageInfo cv)", e
322: // .getLocalizedMessage(), e);
323: // }
324: tempResponse.append("\n <domainSet>");
325: tempResponse.append("\n <spatialDomain>");
326: // Envelope
327: tempResponse
328: .append("\n <gml:Envelope")
329: .append(
330: (((cv.getSrsName() != null) && (cv.getSrsName() != "")) ? new StringBuffer(
331: " srsName=\"").append(cv.getSrsName())
332: .append("\"").toString()
333: : "")).append(">");
334: tempResponse.append("\n <gml:pos>").append(
335: (cvEnvelope != null) ? new StringBuffer(Double
336: .toString(cvEnvelope.getLowerCorner()
337: .getOrdinate(0))).append(" ").append(
338: cvEnvelope.getLowerCorner().getOrdinate(1))
339: .toString() : "").append("</gml:pos>");
340: tempResponse.append("\n <gml:pos>").append(
341: (cvEnvelope != null) ? new StringBuffer(Double
342: .toString(cvEnvelope.getUpperCorner()
343: .getOrdinate(0))).append(" ").append(
344: cvEnvelope.getUpperCorner().getOrdinate(1))
345: .toString() : "").append("</gml:pos>");
346: tempResponse.append("\n </gml:Envelope>");
347:
348: // Grid
349: GridGeometry grid = cv.getGrid();
350: MathTransform gridToCRS = grid.getGridToCRS();
351: InternationalString[] dimNames = cv.getDimensionNames();
352: final int gridDimension = gridToCRS != null ? gridToCRS
353: .getSourceDimensions() : 0;
354:
355: // RectifiedGrid
356: tempResponse.append("\n <gml:RectifiedGrid").append(
357: (gridToCRS != null) ? new StringBuffer(" dimension=\"")
358: .append(gridDimension).append("\"").toString()
359: : "").append(">");
360:
361: String lowers = "";
362: String upers = "";
363:
364: for (int r = 0; r < gridDimension; r++) {
365: lowers += (grid.getGridRange().getLower(r) + " ");
366: upers += (grid.getGridRange().getUpper(r) + " ");
367: }
368:
369: tempResponse.append("\n <gml:limits>");
370: tempResponse.append("\n <gml:GridEnvelope>");
371: tempResponse.append("\n <gml:low>"
372: + ((cvEnvelope != null) ? lowers : "") + "</gml:low>");
373: tempResponse.append("\n <gml:high>"
374: + ((cvEnvelope != null) ? upers : "") + "</gml:high>");
375: tempResponse.append("\n </gml:GridEnvelope>");
376: tempResponse.append("\n </gml:limits>");
377:
378: if (dimNames != null) {
379: for (int dn = 0; dn < dimNames.length; dn++)
380: tempResponse.append("\n <gml:axisName>"
381: + dimNames[dn] + "</gml:axisName>");
382: }
383:
384: tempResponse.append("\n <gml:origin>");
385: tempResponse.append("\n <gml:pos>"
386: + (gridToCRS != null ? ((AffineTransform) gridToCRS)
387: .getTranslateX()
388: + " "
389: + ((AffineTransform) gridToCRS).getTranslateY()
390: : ((cvEnvelope != null) ? (cvEnvelope
391: .getLowerCorner().getOrdinate(0)
392: + " " + cvEnvelope.getUpperCorner()
393: .getOrdinate(1)) : "")) + "</gml:pos>");
394: tempResponse.append("\n </gml:origin>");
395: tempResponse
396: .append("\n <gml:offsetVector>"
397: + (gridToCRS != null ? ((AffineTransform) gridToCRS)
398: .getScaleX()
399: + " "
400: + ((AffineTransform) gridToCRS)
401: .getShearX()
402: : ((cvEnvelope != null) ? ((cvEnvelope
403: .getUpperCorner()
404: .getOrdinate(0) - cvEnvelope
405: .getLowerCorner()
406: .getOrdinate(0)) / (grid
407: .getGridRange().getUpper(0) - grid
408: .getGridRange().getLower(0)))
409: : 0.0)
410: + " 0.0")
411: + "</gml:offsetVector>");
412: tempResponse
413: .append("\n <gml:offsetVector>"
414: + (gridToCRS != null ? ((AffineTransform) gridToCRS)
415: .getShearY()
416: + " "
417: + ((AffineTransform) gridToCRS)
418: .getScaleY()
419: : "0.0 "
420: + ((cvEnvelope != null) ? ((cvEnvelope
421: .getLowerCorner()
422: .getOrdinate(1) - cvEnvelope
423: .getUpperCorner()
424: .getOrdinate(1)) / (grid
425: .getGridRange()
426: .getUpper(1) - grid
427: .getGridRange()
428: .getLower(1)))
429: : -0.0))
430: + "</gml:offsetVector>");
431: tempResponse.append("\n </gml:RectifiedGrid>");
432: tempResponse.append("\n </spatialDomain>");
433:
434: tempResponse.append("\n </domainSet>");
435:
436: // rangeSet
437: CoverageDimension[] dims = cv.getDimensions();
438: TreeSet nodataValues = new TreeSet();
439:
440: try {
441: if (dims != null) {
442: int numSampleDimensions = dims.length;
443: tempResponse.append("\n <rangeSet>");
444: tempResponse.append("\n <RangeSet>");
445: //tempResponse.append("\n <!-- WARNING: Mandatory metadata '..._rangeset_name' was missing in this context. --> ");
446: tempResponse.append("\n <name>" + cv.getName()
447: + "</name>");
448: tempResponse.append("\n <label>" + cv.getLabel()
449: + "</label>");
450: tempResponse.append("\n <axisDescription>");
451: tempResponse.append("\n <AxisDescription>");
452: tempResponse.append("\n <name>Band</name>");
453: tempResponse.append("\n <label>Band</label>");
454: tempResponse.append("\n <values>");
455:
456: if (numSampleDimensions == 1) {
457: tempResponse.append("\n <singleValue>")
458: .append("1").append("</singleValue>");
459: } else {
460: tempResponse.append("\n <interval>");
461: tempResponse.append("\n <min>1</min>");
462: tempResponse.append("\n <max>"
463: + numSampleDimensions + "</max>");
464: tempResponse.append("\n </interval>");
465: }
466:
467: tempResponse.append("\n </values>");
468: tempResponse.append("\n </AxisDescription>");
469: tempResponse.append("\n </axisDescription>");
470:
471: for (int sample = 0; sample < numSampleDimensions; sample++) {
472: Double[] nodata = dims[sample].getNullValues();
473:
474: if (nodata != null) {
475: for (int nd = 0; nd < nodata.length; nd++) {
476: if (!nodataValues.contains(nodata[nd])) {
477: nodataValues.add(nodata[nd]);
478: }
479: }
480: }
481: }
482:
483: tempResponse.append("\n <nullValues>");
484:
485: if (nodataValues.size() > 0) {
486: if (nodataValues.size() == 1) {
487: tempResponse.append("\n <singleValue>"
488: + (Double) nodataValues.first()
489: + "</singleValue>");
490: } else {
491: tempResponse.append("\n <interval>");
492: tempResponse.append("\n <min>"
493: + (Double) nodataValues.first()
494: + "</min>");
495: tempResponse.append("\n <max>"
496: + (Double) nodataValues.last()
497: + "</max>");
498: tempResponse.append("\n <interval>");
499: }
500: } else {
501: tempResponse
502: .append("\n <singleValue>0</singleValue>");
503: }
504:
505: tempResponse.append("\n </nullValues>");
506:
507: tempResponse.append("\n </RangeSet>");
508: tempResponse.append("\n </rangeSet>");
509: }
510: } catch (Exception e) {
511: // TODO Handle this exceptions ...
512: e.printStackTrace();
513: }
514:
515: if (((cv.getRequestCRSs() != null) && (cv.getRequestCRSs()
516: .size() > 0))
517: || ((cv.getResponseCRSs() != null) && (cv
518: .getResponseCRSs().size() > 0))) {
519: tempResponse.append("\n <supportedCRSs>");
520:
521: if ((cv.getResponseCRSs() != null)
522: && (cv.getResponseCRSs().size() > 0)
523: && (cv.getRequestCRSs() != null)
524: && (cv.getRequestCRSs().size() > 0)) {
525: tempResponse.append("\n <requestResponseCRSs>");
526:
527: ArrayList CRSs = new ArrayList();
528:
529: for (int i = 0; i < cv.getRequestCRSs().size(); i++)
530: if (!CRSs.contains(cv.getRequestCRSs().get(i))) {
531: CRSs.add(cv.getRequestCRSs().get(i));
532: }
533:
534: for (int i = 0; i < cv.getResponseCRSs().size(); i++)
535: if (!CRSs.contains(cv.getResponseCRSs().get(i))) {
536: CRSs.add(cv.getResponseCRSs().get(i));
537: }
538:
539: for (int i = 0; i < CRSs.size(); i++)
540: tempResponse.append(CRSs.get(i) + " ");
541:
542: tempResponse.append("\n </requestResponseCRSs>");
543: } else {
544: if ((cv.getRequestCRSs() != null)
545: && (cv.getRequestCRSs().size() > 0)) {
546: for (int i = 0; i < cv.getRequestCRSs().size(); i++)
547: tempResponse.append("\n <requestCRSs>"
548: + cv.getRequestCRSs().get(i)
549: + "</requestCRSs>");
550: }
551:
552: if ((cv.getResponseCRSs() != null)
553: && (cv.getResponseCRSs().size() > 0)) {
554: for (int i = 0; i < cv.getResponseCRSs().size(); i++)
555: tempResponse.append("\n <responseCRSs>"
556: + cv.getResponseCRSs().get(i)
557: + "</responseCRSs>");
558: }
559: }
560:
561: tempResponse.append("\n </supportedCRSs>");
562: }
563:
564: final String nativeFormat = (((cv.getNativeFormat() != null) && cv
565: .getNativeFormat().equalsIgnoreCase("GEOTIFF")) ? "GeoTIFF"
566: : cv.getNativeFormat());
567: String supportedFormat = "";
568:
569: if (((cv.getSupportedFormats() != null) && (cv
570: .getSupportedFormats().size() > 0))) {
571: tempResponse
572: .append("\n <supportedFormats"
573: + (((nativeFormat != null) && (nativeFormat != "")) ? (" nativeFormat=\""
574: + nativeFormat + "\"")
575: : "") + ">");
576:
577: for (int i = 0; i < cv.getSupportedFormats().size(); i++) {
578: supportedFormat = (String) cv.getSupportedFormats()
579: .get(i);
580: supportedFormat = (supportedFormat
581: .equalsIgnoreCase("GEOTIFF") ? "GeoTIFF"
582: : supportedFormat);
583: tempResponse.append("\n <formats>" + supportedFormat
584: + "</formats>");
585: }
586:
587: tempResponse.append("\n </supportedFormats>");
588: }
589:
590: if (((cv.getInterpolationMethods() != null) && (cv
591: .getInterpolationMethods().size() > 0))) {
592: tempResponse
593: .append("\n <supportedInterpolations"
594: + (((cv.getDefaultInterpolationMethod() != null) && (cv
595: .getDefaultInterpolationMethod() != "")) ? (" default=\""
596: + cv
597: .getDefaultInterpolationMethod() + "\"")
598: : "") + ">");
599:
600: for (int i = 0; i < cv.getInterpolationMethods().size(); i++)
601: tempResponse.append("\n <interpolationMethod>"
602: + cv.getInterpolationMethods().get(i)
603: + "</interpolationMethod>");
604:
605: tempResponse.append("\n </supportedInterpolations>");
606: }
607:
608: tempResponse.append("\n </CoverageOffering>");
609:
610: return tempResponse.toString();
611: } /*
612: * (non-Javadoc)
613: *
614: * @see org.vfny.geoserver.responses.Response#abort()
615: */
616:
617: public void abort(Service gs) {
618: // nothing to undo
619: }
620: }
|