/** * Returns the default value for elevation dimension. * * @param resourceInfo * @return */ public Double getDefaultElevation(ResourceInfo resourceInfo) { DimensionInfo elevation = resourceInfo.getMetadata().get(ResourceInfo.ELEVATION, DimensionInfo.class); if (elevation == null || !elevation.isEnabled()) { throw new ServiceException( "Layer " + resourceInfo.prefixedName() + " does not have elevation support enabled"); } DimensionDefaultValueSelectionStrategy strategy = this.getDefaultValueStrategy(resourceInfo, ResourceInfo.ELEVATION, elevation); return strategy.getDefaultValue(resourceInfo, ResourceInfo.ELEVATION, elevation, Double.class); }
/** * Returns the default value for time dimension. * * @param resourceInfo * @return */ public Date getDefaultTime(ResourceInfo resourceInfo) { // check the time metadata DimensionInfo time = resourceInfo.getMetadata().get(ResourceInfo.TIME, DimensionInfo.class); if (time == null || !time.isEnabled()) { throw new ServiceException( "Layer " + resourceInfo.prefixedName() + " does not have time support enabled"); } DimensionDefaultValueSelectionStrategy strategy = this.getDefaultValueStrategy(resourceInfo, ResourceInfo.TIME, time); return strategy.getDefaultValue(resourceInfo, ResourceInfo.TIME, time, Date.class); }
/** @param referencedEnvelope */ private void handleEnvelope( ReferencedEnvelope referencedEnvelope, DimensionInfo timeInfo, ReaderDimensionsAccessor dimensions) { AttributesImpl attributes = new AttributesImpl(); attributes.addAttribute( "", "srsName", "srsName", "", /* "WGS84(DD)" */ "urn:ogc:def:crs:OGC:1.3:CRS84"); start("wcs:lonLatEnvelope", attributes); final StringBuffer minCP = new StringBuffer(Double.toString(referencedEnvelope.getMinX())) .append(" ") .append(referencedEnvelope.getMinY()); final StringBuffer maxCP = new StringBuffer(Double.toString(referencedEnvelope.getMaxX())) .append(" ") .append(referencedEnvelope.getMaxY()); element("gml:pos", minCP.toString()); element("gml:pos", maxCP.toString()); // are we going to report time? if (timeInfo != null && timeInfo.isEnabled()) { SimpleDateFormat timeFormat = dimensions.getTimeFormat(); element("gml:timePosition", timeFormat.format(dimensions.getMinTime())); element("gml:timePosition", timeFormat.format(dimensions.getMaxTime())); } end("wcs:lonLatEnvelope"); }
/** * Returns the default value for the given custom dimension. * * @param <T> * @param dimensionName * @param resourceInfo * @param clz * @return */ public <T> T getDefaultCustomDimensionValue( String dimensionName, ResourceInfo resourceInfo, Class<T> clz) { DimensionInfo customDim = resourceInfo .getMetadata() .get(ResourceInfo.CUSTOM_DIMENSION_PREFIX + dimensionName, DimensionInfo.class); if (customDim == null || !customDim.isEnabled()) { throw new ServiceException( "Layer " + resourceInfo.prefixedName() + " does not have support enabled for dimension " + dimensionName); } DimensionDefaultValueSelectionStrategy strategy = this.getDefaultValueStrategy( resourceInfo, ResourceInfo.CUSTOM_DIMENSION_PREFIX + dimensionName, customDim); return strategy.getDefaultValue( resourceInfo, ResourceInfo.CUSTOM_DIMENSION_PREFIX + dimensionName, customDim, clz); }
/** * Set the timeDomain metadata in case the dimensionsHelper instance has a timeDimension * * @param helper * @throws IOException */ private void handleTimeMetadata(WCSDimensionsHelper helper) throws IOException { Utilities.ensureNonNull("helper", helper); final DimensionInfo timeDimension = helper.getTimeDimension(); if (timeDimension != null) { start(initStartMetadataTag(TAG.TIME_DOMAIN, null, timeDimension, helper)); final DimensionPresentation presentation = timeDimension.getPresentation(); final String id = helper.getCoverageId(); switch (presentation) { case CONTINUOUS_INTERVAL: encodeTimePeriod(helper.getBeginTime(), helper.getEndTime(), id + "_tp_0", null, null); break; case DISCRETE_INTERVAL: encodeTimePeriod( helper.getBeginTime(), helper.getEndTime(), id + "_tp_0", helper.getTimeResolutionUnit(), helper.getTimeResolutionValue()); break; default: // TODO: check if we are in the list of instants case, or in the list of periods case // list case final TreeSet<Object> domain = helper.getTimeDomain(); int i = 0; for (Object item : domain) { // gml:id is mandatory for time instant... if (item instanceof Date) { encodeDate((Date) item, helper, id + "_td_" + i); } else if (item instanceof DateRange) { encodeDateRange((DateRange) item, helper, id + "_td_" + i); } i++; } break; } end(TAG.TIME_DOMAIN); } }
/** * Set the elevationDomain metadata in case the dimensionsHelper instance has an * elevationDimension * * @param helper * @throws IOException */ private void handleElevationMetadata(WCSDimensionsHelper helper) throws IOException { // Null check has been performed in advance final DimensionInfo elevationDimension = helper.getElevationDimension(); if (elevationDimension != null) { start(initStartMetadataTag(TAG.ELEVATION_DOMAIN, null, elevationDimension, helper)); final DimensionPresentation presentation = elevationDimension.getPresentation(); switch (presentation) { // Where _er_ means elevation range case CONTINUOUS_INTERVAL: encodeInterval(helper.getBeginElevation(), helper.getEndElevation(), null, null); break; case DISCRETE_INTERVAL: encodeInterval( helper.getBeginElevation(), helper.getEndElevation(), helper.getElevationResolutionUnit(), helper.getElevationResolutionValue()); break; default: // TODO: check if we are in the list of instants case, or in the list of periods case // list case final TreeSet<Object> domain = helper.getElevationDomain(); for (Object item : domain) { if (item instanceof Number) { element(TAG.SINGLE_VALUE, item.toString()); } else if (item instanceof NumberRange) { NumberRange range = (NumberRange) item; encodeInterval( range.getMinValue().toString(), range.getMaxValue().toString(), null, null); } } break; } end(TAG.ELEVATION_DOMAIN); } }
/** * Returns the list of elevation values for the specified typeInfo based on the dimension * representation: all values for {@link DimensionPresentation#LIST}, otherwise min and max * * @param typeInfo * @return * @throws IOException */ public TreeSet<Double> getFeatureTypeElevations(FeatureTypeInfo typeInfo) throws IOException { // grab the time metadata DimensionInfo elevation = typeInfo.getMetadata().get(ResourceInfo.ELEVATION, DimensionInfo.class); if (elevation == null || !elevation.isEnabled()) { throw new ServiceException( "Layer " + typeInfo.getPrefixedName() + " does not have elevation support enabled"); } FeatureCollection collection = getDimensionCollection(typeInfo, elevation); TreeSet<Double> result = new TreeSet<Double>(); if (elevation.getPresentation() == DimensionPresentation.LIST || (elevation.getPresentation() == DimensionPresentation.DISCRETE_INTERVAL && elevation.getResolution() == null)) { final UniqueVisitor visitor = new UniqueVisitor(elevation.getAttribute()); collection.accepts(visitor, null); @SuppressWarnings("unchecked") Set<Object> values = visitor.getUnique(); if (values.size() <= 0) { result = null; } else { for (Object value : values) { result.add(((Number) value).doubleValue()); } } } else { final MinVisitor min = new MinVisitor(elevation.getAttribute()); collection.accepts(min, null); // check calcresult first to avoid potential IllegalStateException if no features are in // collection CalcResult calcResult = min.getResult(); if (calcResult != CalcResult.NULL_RESULT) { result.add(((Number) min.getMin()).doubleValue()); final MaxVisitor max = new MaxVisitor(elevation.getAttribute()); collection.accepts(max, null); result.add(((Number) max.getMax()).doubleValue()); } } return result; }
/** * Returns the collection of all values of the dimension attribute, eventually sorted if the * native capabilities allow for it * * @param typeInfo * @param dimension * @return * @throws IOException */ FeatureCollection getDimensionCollection(FeatureTypeInfo typeInfo, DimensionInfo dimension) throws IOException { // grab the feature source FeatureSource source = null; try { source = typeInfo.getFeatureSource(null, GeoTools.getDefaultHints()); } catch (IOException e) { throw new ServiceException( "Could not get the feauture source to list time info for layer " + typeInfo.getPrefixedName(), e); } // build query to grab the dimension values final Query dimQuery = new Query(source.getSchema().getName().getLocalPart()); dimQuery.setPropertyNames(Arrays.asList(dimension.getAttribute())); return source.getFeatures(dimQuery); }
/** * Builds a filter for the current time and elevation, should the layer support them. Only one * among time and elevation can be multi-valued * * @param layerFilter * @param currentTime * @param currentElevation * @param mapLayerInfo * @return */ public Filter getTimeElevationToFilter( List<Object> times, List<Object> elevations, FeatureTypeInfo typeInfo) throws IOException { DimensionInfo timeInfo = typeInfo.getMetadata().get(ResourceInfo.TIME, DimensionInfo.class); DimensionInfo elevationInfo = typeInfo.getMetadata().get(ResourceInfo.ELEVATION, DimensionInfo.class); DimensionFilterBuilder builder = new DimensionFilterBuilder(ff); // handle time support if (timeInfo != null && timeInfo.isEnabled() && times != null) { List<Object> defaultedTimes = new ArrayList<Object>(times.size()); for (Object datetime : times) { if (datetime == null) { // this is "default" datetime = getDefaultTime(typeInfo); } defaultedTimes.add(datetime); } builder.appendFilters(timeInfo.getAttribute(), timeInfo.getEndAttribute(), defaultedTimes); } // handle elevation support if (elevationInfo != null && elevationInfo.isEnabled() && elevations != null) { List<Object> defaultedElevations = new ArrayList<Object>(elevations.size()); for (Object elevation : elevations) { if (elevation == null) { // this is "default" elevation = getDefaultElevation(typeInfo); } defaultedElevations.add(elevation); } builder.appendFilters( elevationInfo.getAttribute(), elevationInfo.getEndAttribute(), defaultedElevations); } Filter result = builder.getFilter(); return result; }
/** * Initialize the metadata start tag for a custom dimension, setting dimension name, checking * for UOM, defaultValue, ... * * @param dimensionTag the TAG referring to type of dimension (Time, Elevation, Additional ,...) * @param name the name of the custom dimension * @param dimension the custom dimension {@link DimensionInfo} instance * @param helper the {@link WCSDimensionsHelper} instance used to parse default values * @return * @throws IOException */ private String initStartMetadataTag( final String dimensionTag, final String name, final DimensionInfo dimension, final WCSDimensionsHelper helper) throws IOException { final String uom = dimension.getUnitSymbol(); String defaultValue = null; String prolog = null; if (dimensionTag.equals(TAG.ADDITIONAL_DIMENSION)) { prolog = TAG.ADDITIONAL_DIMENSION + " name = \"" + name + "\""; defaultValue = helper.getDefaultValue(name); } else if (dimensionTag.equals(TAG.ELEVATION_DOMAIN)) { prolog = TAG.ELEVATION_DOMAIN; defaultValue = helper.getBeginElevation(); } else if (dimensionTag.equals(TAG.TIME_DOMAIN)) { prolog = TAG.TIME_DOMAIN; defaultValue = helper.getEndTime(); } return prolog + (uom != null ? (" uom=\"" + uom + "\"") : "") + (defaultValue != null ? (" default=\"" + defaultValue + "\"") : ""); }
/** * Returns the list of time values for the specified typeInfo based on the dimension * representation: all values for {@link DimensionPresentation#LIST}, otherwise min and max * * @param typeInfo * @return * @throws IOException */ public TreeSet<Date> getFeatureTypeTimes(FeatureTypeInfo typeInfo) throws IOException { // grab the time metadata DimensionInfo time = typeInfo.getMetadata().get(ResourceInfo.TIME, DimensionInfo.class); if (time == null || !time.isEnabled()) { throw new ServiceException( "Layer " + typeInfo.getPrefixedName() + " does not have time support enabled"); } FeatureCollection collection = getDimensionCollection(typeInfo, time); TreeSet<Date> result = new TreeSet<Date>(); if (time.getPresentation() == DimensionPresentation.LIST) { final UniqueVisitor visitor = new UniqueVisitor(time.getAttribute()); collection.accepts(visitor, null); @SuppressWarnings("unchecked") Set<Date> values = visitor.getUnique(); if (values.size() <= 0) { result = null; } else { // we might get null values out of the visitor, strip them values.remove(null); result.addAll(values); } } else { final MinVisitor min = new MinVisitor(time.getAttribute()); collection.accepts(min, null); CalcResult minResult = min.getResult(); // check calcresult first to avoid potential IllegalStateException if no features are in // collection if (minResult != CalcResult.NULL_RESULT) { result.add((Date) min.getMin()); final MaxVisitor max = new MaxVisitor(time.getAttribute()); collection.accepts(max, null); result.add((Date) max.getMax()); } } return result; }
/** * Returns the read parameters for the specified layer, merging some well known request parameters * into the read parameters if possible * * @param request * @param mapLayerInfo * @param layerFilter * @param reader * @return */ public GeneralParameterValue[] getWMSReadParameters( final GetMapRequest request, final MapLayerInfo mapLayerInfo, final Filter layerFilter, final List<Object> times, final List<Object> elevations, final GridCoverage2DReader reader, boolean readGeom) throws IOException { // setup the scene final ParameterValueGroup readParametersDescriptor = reader.getFormat().getReadParameters(); CoverageInfo coverage = mapLayerInfo.getCoverage(); MetadataMap metadata = coverage.getMetadata(); GeneralParameterValue[] readParameters = CoverageUtils.getParameters(readParametersDescriptor, coverage.getParameters(), readGeom); ReaderDimensionsAccessor dimensions = new ReaderDimensionsAccessor(reader); // pass down time final DimensionInfo timeInfo = metadata.get(ResourceInfo.TIME, DimensionInfo.class); // add the descriptors for custom dimensions final List<GeneralParameterDescriptor> parameterDescriptors = new ArrayList<GeneralParameterDescriptor>( readParametersDescriptor.getDescriptor().descriptors()); Set<ParameterDescriptor<List>> dynamicParameters = reader.getDynamicParameters(); parameterDescriptors.addAll(dynamicParameters); if (timeInfo != null && timeInfo.isEnabled()) { // handle "default" List<Object> fixedTimes = new ArrayList<Object>(times); for (int i = 0; i < fixedTimes.size(); i++) { if (fixedTimes.get(i) == null) { fixedTimes.set(i, getDefaultTime(coverage)); } } // pass down the parameters readParameters = CoverageUtils.mergeParameter( parameterDescriptors, readParameters, fixedTimes, "TIME", "Time"); } // pass down elevation final DimensionInfo elevationInfo = metadata.get(ResourceInfo.ELEVATION, DimensionInfo.class); if (elevationInfo != null && elevationInfo.isEnabled()) { // handle "default" List<Object> fixedElevations = new ArrayList<Object>(elevations); for (int i = 0; i < fixedElevations.size(); i++) { if (fixedElevations.get(i) == null) { fixedElevations.set(i, getDefaultElevation(coverage)); } } readParameters = CoverageUtils.mergeParameter( parameterDescriptors, readParameters, fixedElevations, "ELEVATION", "Elevation"); } if (layerFilter != null && readParameters != null) { // test for default [empty is replaced with INCLUDE filter] ]filter for (int i = 0; i < readParameters.length; i++) { GeneralParameterValue param = readParameters[i]; GeneralParameterDescriptor pd = param.getDescriptor(); if (pd.getName().getCode().equalsIgnoreCase("FILTER")) { final ParameterValue pv = (ParameterValue) pd.createValue(); // if something different from the default INCLUDE filter is specified if (layerFilter != Filter.INCLUDE) { // override the default filter pv.setValue(layerFilter); readParameters[i] = pv; } break; } } } // custom dimensions List<String> customDomains = new ArrayList(dimensions.getCustomDomains()); for (String domain : new ArrayList<String>(customDomains)) { List<String> values = request.getCustomDimension(domain); if (values != null) { readParameters = CoverageUtils.mergeParameter(parameterDescriptors, readParameters, values, domain); customDomains.remove(domain); } } // see if we have any custom domain for which we have to set the default value if (!customDomains.isEmpty()) { for (String name : customDomains) { final DimensionInfo customInfo = metadata.get(ResourceInfo.CUSTOM_DIMENSION_PREFIX + name, DimensionInfo.class); if (customInfo != null && customInfo.isEnabled()) { final ArrayList<String> val = new ArrayList<String>(1); val.add(getDefaultCustomDimensionValue(name, coverage, String.class)); readParameters = CoverageUtils.mergeParameter(parameterDescriptors, readParameters, val, name); } } } return readParameters; }