/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2014 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wms.dimension.impl; import java.text.ParseException; import java.util.Collection; import java.util.Date; import org.geoserver.catalog.CoverageInfo; import org.geoserver.catalog.DimensionDefaultValueSetting; import org.geoserver.catalog.DimensionDefaultValueSetting.Strategy; import org.geoserver.catalog.DimensionInfo; import org.geoserver.catalog.FeatureTypeInfo; import org.geoserver.catalog.ResourceInfo; import org.geoserver.ows.kvp.ElevationParser; import org.geoserver.ows.kvp.TimeParser; import org.geoserver.platform.ServiceException; import org.geoserver.wms.dimension.DimensionDefaultValueSelectionStrategy; import org.geoserver.wms.dimension.DimensionDefaultValueSelectionStrategyFactory; import org.geoserver.wms.dimension.FixedValueStrategyFactory; import org.geoserver.wms.dimension.NearestValueStrategyFactory; import org.geotools.feature.type.DateUtil; /** * The default implementation of the {@link DimensionDefaultValueSelectionStrategyFactory}. * Uses strategies and strategy factories injected by the WMS application * context. Thus to change the default value selection strategy * implementations one typically only needs to inject another * strategy of strategy factory (for NEAREST and FIXED strategies). * * Supports default value selection for TIME, ELEVATION and custom * dimensions for both coverage and feature resources. * * * @author Ilkka Rinne / Spatineo Inc for the Finnish Meteorological Institute * */ public class DimensionDefaultValueSelectionStrategyFactoryImpl implements DimensionDefaultValueSelectionStrategyFactory { // Initialized in the applicationContext: private DimensionDefaultValueSelectionStrategy featureTimeMinimumStrategy; private DimensionDefaultValueSelectionStrategy featureTimeMaximumStrategy; private DimensionDefaultValueSelectionStrategy coverageTimeMinimumStrategy; private DimensionDefaultValueSelectionStrategy coverageTimeMaximumStrategy; private DimensionDefaultValueSelectionStrategy featureElevationMinimumStrategy; private DimensionDefaultValueSelectionStrategy featureElevationMaximumStrategy; private DimensionDefaultValueSelectionStrategy coverageElevationMinimumStrategy; private DimensionDefaultValueSelectionStrategy coverageElevationMaximumStrategy; private DimensionDefaultValueSelectionStrategy featureCustomDimensionMinimumStrategy; private DimensionDefaultValueSelectionStrategy featureCustomDimensionMaximumStrategy; private DimensionDefaultValueSelectionStrategy coverageCustomDimensionMinimumStrategy; private DimensionDefaultValueSelectionStrategy coverageCustomDimensionMaximumStrategy; private NearestValueStrategyFactory featureNearestValueStrategyFactory; private NearestValueStrategyFactory coverageNearestValueStrategyFactory; private FixedValueStrategyFactory fixedValueStrategyFactory; private TimeParser timeParser = new TimeParser(); private ElevationParser elevationParser = new ElevationParser(); /** * Return the default value strategy for the given dimension. If the default value strategy setting * is not set for this dimension, returns the default strategy for this resource type. */ @Override public DimensionDefaultValueSelectionStrategy getStrategy(ResourceInfo resource, String dimensionName, DimensionInfo dimensionInfo) { DimensionDefaultValueSelectionStrategy retval = getStrategyFromSetting(resource, dimensionName, dimensionInfo); if (retval != null) { return retval; } // Else just select the default strategy based on the dimension name if (dimensionName.equals(ResourceInfo.TIME)) { if (resource instanceof FeatureTypeInfo) { retval = featureNearestValueStrategyFactory.createNearestValueStrategy(new Date(), DimensionDefaultValueSetting.TIME_CURRENT); } else if (resource instanceof CoverageInfo) { retval = coverageNearestValueStrategyFactory.createNearestValueStrategy(new Date(), DimensionDefaultValueSetting.TIME_CURRENT); } } else if (dimensionName.equals(ResourceInfo.ELEVATION)) { if (resource instanceof FeatureTypeInfo) { retval = featureElevationMinimumStrategy; } else if (resource instanceof CoverageInfo) { retval = coverageElevationMinimumStrategy; } } else if (dimensionName.startsWith(ResourceInfo.CUSTOM_DIMENSION_PREFIX)) { if (resource instanceof FeatureTypeInfo) { retval = featureCustomDimensionMinimumStrategy; } else if (resource instanceof CoverageInfo) { retval = coverageCustomDimensionMinimumStrategy; } } return retval; } /** * @return the featureTimeMinimumStrategy */ public DimensionDefaultValueSelectionStrategy getFeatureTimeMinimumStrategy() { return featureTimeMinimumStrategy; } /** * @param featureTimeMinimumStrategy the featureTimeMinimumStrategy to set */ public void setFeatureTimeMinimumStrategy( DimensionDefaultValueSelectionStrategy featureTimeMinimumStrategy) { this.featureTimeMinimumStrategy = featureTimeMinimumStrategy; } /** * @return the featureTimeMaximumStrategy */ public DimensionDefaultValueSelectionStrategy getFeatureTimeMaximumStrategy() { return featureTimeMaximumStrategy; } /** * @param featureTimeMaximumStrategy the featureTimeMaximumStrategy to set */ public void setFeatureTimeMaximumStrategy( DimensionDefaultValueSelectionStrategy featureTimeMaximumStrategy) { this.featureTimeMaximumStrategy = featureTimeMaximumStrategy; } /** * @return the coverageTimeMinimumStrategy */ public DimensionDefaultValueSelectionStrategy getCoverageTimeMinimumStrategy() { return coverageTimeMinimumStrategy; } /** * @param coverageTimeMinimumStrategy the coverageTimeMinimumStrategy to set */ public void setCoverageTimeMinimumStrategy( DimensionDefaultValueSelectionStrategy coverageTimeMinimumStrategy) { this.coverageTimeMinimumStrategy = coverageTimeMinimumStrategy; } /** * @return the coverageTimeMaximumStrategy */ public DimensionDefaultValueSelectionStrategy getCoverageTimeMaximumStrategy() { return coverageTimeMaximumStrategy; } /** * @param coverageTimeMaximumStrategy the coverageTimeMaximumStrategy to set */ public void setCoverageTimeMaximumStrategy( DimensionDefaultValueSelectionStrategy coverageTimeMaximumStrategy) { this.coverageTimeMaximumStrategy = coverageTimeMaximumStrategy; } /** * @return the featureElevationMiminumStrategy */ public DimensionDefaultValueSelectionStrategy getFeatureElevationMinimumStrategy() { return featureElevationMinimumStrategy; } /** * @param featureElevationMiminumStrategy the featureElevationMiminumStrategy to set */ public void setFeatureElevationMinimumStrategy( DimensionDefaultValueSelectionStrategy featureElevationMinimumStrategy) { this.featureElevationMinimumStrategy = featureElevationMinimumStrategy; } /** * @return the featureElevationMaximumStrategy */ public DimensionDefaultValueSelectionStrategy getFeatureElevationMaximumStrategy() { return featureElevationMaximumStrategy; } /** * @param featureElevationMaxinumStrategy the featureElevationMaxinumStrategy to set */ public void setFeatureElevationMaximumStrategy( DimensionDefaultValueSelectionStrategy featureElevationMaximumStrategy) { this.featureElevationMaximumStrategy = featureElevationMaximumStrategy; } /** * @return the coverageElevationMinimumStrategy */ public DimensionDefaultValueSelectionStrategy getCoverageElevationMinimumStrategy() { return coverageElevationMinimumStrategy; } /** * @param coverageElevationMinimumStrategy the coverageElevationMinimumStrategy to set */ public void setCoverageElevationMinimumStrategy( DimensionDefaultValueSelectionStrategy coverageElevationMinimumStrategy) { this.coverageElevationMinimumStrategy = coverageElevationMinimumStrategy; } /** * @return the coverageElevationMaximumStrategy */ public DimensionDefaultValueSelectionStrategy getCoverageElevationMaximumStrategy() { return coverageElevationMaximumStrategy; } /** * @param coverageElevationMaximumStrategy the coverageElevationMaximumStrategy to set */ public void setCoverageElevationMaximumStrategy( DimensionDefaultValueSelectionStrategy coverageElevationMaximumStrategy) { this.coverageElevationMaximumStrategy = coverageElevationMaximumStrategy; } /** * @return the featureCustomDimensionMinimumStrategy */ public DimensionDefaultValueSelectionStrategy getFeatureCustomDimensionMinimumStrategy() { return featureCustomDimensionMinimumStrategy; } /** * @param featureCustomDimensionMinimumStrategy the featureCustomDimensionMinimumStrategy to set */ public void setFeatureCustomDimensionMinimumStrategy( DimensionDefaultValueSelectionStrategy featureCustomDimensionMinimumStrategy) { this.featureCustomDimensionMinimumStrategy = featureCustomDimensionMinimumStrategy; } /** * @return the featureCustomDimensionMaximumStrategy */ public DimensionDefaultValueSelectionStrategy getFeatureCustomDimensionMaximumStrategy() { return featureCustomDimensionMaximumStrategy; } /** * @param featureCustomDimensionMaximumStrategy the featureCustomDimensionMaximumStrategy to set */ public void setFeatureCustomDimensionMaximumStrategy( DimensionDefaultValueSelectionStrategy featureCustomDimensionMaximumStrategy) { this.featureCustomDimensionMaximumStrategy = featureCustomDimensionMaximumStrategy; } /** * @return the coverageCustomDimensionMinimumStrategy */ public DimensionDefaultValueSelectionStrategy getCoverageCustomDimensionMinimumStrategy() { return coverageCustomDimensionMinimumStrategy; } /** * @param coverageCustomDimensionMinimumStrategy the coverageCustomDimensionMinimumStrategy to set */ public void setCoverageCustomDimensionMinimumStrategy( DimensionDefaultValueSelectionStrategy coverageCustomDimensionMinimumStrategy) { this.coverageCustomDimensionMinimumStrategy = coverageCustomDimensionMinimumStrategy; } /** * @return the coverageCustomDimensionMaximumStrategy */ public DimensionDefaultValueSelectionStrategy getCoverageCustomDimensionMaximumStrategy() { return coverageCustomDimensionMaximumStrategy; } /** * @param coverageCustomDimensionMaximumStrategy the coverageCustomDimensionMaximumStrategy to set */ public void setCoverageCustomDimensionMaximumStrategy( DimensionDefaultValueSelectionStrategy coverageCustomDimensionMaximumStrategy) { this.coverageCustomDimensionMaximumStrategy = coverageCustomDimensionMaximumStrategy; } /** * @return the featureNearestValueStrategyFactory */ public NearestValueStrategyFactory getFeatureNearestValueStrategyFactory() { return featureNearestValueStrategyFactory; } /** * @param featureNearestValueStrategyFactory the featureNearestValueStrategyFactory to set */ public void setFeatureNearestValueStrategyFactory( NearestValueStrategyFactory featureNearestValueStrategyFactory) { this.featureNearestValueStrategyFactory = featureNearestValueStrategyFactory; } /** * @return the coverageNearestValueStrategyFactory */ public NearestValueStrategyFactory getCoverageNearestValueStrategyFactory() { return coverageNearestValueStrategyFactory; } /** * @param coverageNearestValueStrategyFactory the coverageNearestValueStrategyFactory to set */ public void setCoverageNearestValueStrategyFactory( NearestValueStrategyFactory coverageNearestValueStrategyFactory) { this.coverageNearestValueStrategyFactory = coverageNearestValueStrategyFactory; } /** * @return the fixedValueStrategyFactory */ public FixedValueStrategyFactory getFixedValueStrategyFactory() { return fixedValueStrategyFactory; } /** * @param fixedValueStrategyFactory the fixedValueStrategyFactory to set */ public void setFixedValueStrategyFactory(FixedValueStrategyFactory fixedValueStrategyFactory) { this.fixedValueStrategyFactory = fixedValueStrategyFactory; } private DimensionDefaultValueSelectionStrategy getStrategyFromSetting(ResourceInfo resource, String dimensionName, DimensionInfo dimensionInfo) { DimensionDefaultValueSelectionStrategy retval = null; DimensionDefaultValueSetting setting = dimensionInfo.getDefaultValue(); if (setting != null && setting.getStrategyType() != null) { if (dimensionName.equals(ResourceInfo.TIME)) { retval = getDefaultTimeStrategy(resource, setting); } else if (dimensionName.equals(ResourceInfo.ELEVATION)) { retval = getDefaultElevationStrategy(resource, setting); } else if (dimensionName.startsWith(ResourceInfo.CUSTOM_DIMENSION_PREFIX)) { retval = getDefaultCustomDimensionStrategy(resource, setting); } } return retval; } private DimensionDefaultValueSelectionStrategy getDefaultTimeStrategy(ResourceInfo resource, DimensionDefaultValueSetting setting) { DimensionDefaultValueSelectionStrategy retval = null; Strategy getStrategyType = setting.getStrategyType(); switch (getStrategyType) { case NEAREST: { Date refDate; String capabilitiesValue = null; String referenceValue = setting.getReferenceValue(); if (referenceValue != null) { if (referenceValue.equalsIgnoreCase(DimensionDefaultValueSetting.TIME_CURRENT)) { refDate = new Date(); capabilitiesValue = DimensionDefaultValueSetting.TIME_CURRENT; } else { try { refDate = new Date(DateUtil.parseDateTime(referenceValue)); } catch (IllegalArgumentException e) { throw new ServiceException( "Unable to parse time dimension default value reference '" + referenceValue + "' as date, an ISO 8601 datetime format is expected", e); } } if (resource instanceof FeatureTypeInfo) { retval = featureNearestValueStrategyFactory.createNearestValueStrategy(refDate, capabilitiesValue); } else if (resource instanceof CoverageInfo) { retval = coverageNearestValueStrategyFactory.createNearestValueStrategy( refDate, capabilitiesValue); } } else { throw new ServiceException( "No reference value given for time dimension default value 'nearest' strategy"); } break; } case MINIMUM: { if (resource instanceof FeatureTypeInfo) { retval = featureTimeMinimumStrategy; } else if (resource instanceof CoverageInfo) { retval = coverageTimeMinimumStrategy; } break; } case MAXIMUM: { if (resource instanceof FeatureTypeInfo) { retval = featureTimeMaximumStrategy; } else if (resource instanceof CoverageInfo) { retval = coverageTimeMaximumStrategy; } break; } case FIXED: { Object refDate; String referenceValue = setting.getReferenceValue(); if (referenceValue != null) { try { refDate = singleValue(timeParser.parse(referenceValue), new Date()); } catch (ParseException e) { throw new ServiceException( "Unable to parse time dimension default value reference '" + referenceValue + "' as date or a date range, an ISO 8601 datetime format is expected", e); } retval = fixedValueStrategyFactory.createFixedValueStrategy(refDate, referenceValue); } else { throw new ServiceException( "No reference value given for time dimension default value 'fixed' strategy"); } break; } } return retval; } private DimensionDefaultValueSelectionStrategy getDefaultElevationStrategy(ResourceInfo resource, DimensionDefaultValueSetting setting) { DimensionDefaultValueSelectionStrategy retval = null; switch (setting.getStrategyType()) { case NEAREST: { Number refNumber; String referenceValue = setting.getReferenceValue(); if (referenceValue != null) { try { refNumber = Long.parseLong(referenceValue); } catch (NumberFormatException fne) { try { refNumber = Double.parseDouble(referenceValue); } catch (NumberFormatException e) { throw new ServiceException( "Unable to parse elevation dimension default value reference '" + referenceValue + "' as long or double", e); } } if (resource instanceof FeatureTypeInfo) { retval = featureNearestValueStrategyFactory .createNearestValueStrategy(refNumber); } else if (resource instanceof CoverageInfo) { retval = coverageNearestValueStrategyFactory .createNearestValueStrategy(refNumber); } } else { throw new ServiceException( "No reference value given for elevation dimension default value 'nearest' strategy"); } break; } case MINIMUM: { if (resource instanceof FeatureTypeInfo) { retval = featureElevationMinimumStrategy; } else if (resource instanceof CoverageInfo) { retval = coverageElevationMinimumStrategy; } break; } case MAXIMUM: { if (resource instanceof FeatureTypeInfo) { retval = featureElevationMaximumStrategy; } else if (resource instanceof CoverageInfo) { retval = coverageElevationMaximumStrategy; } break; } case FIXED: { Object refNumber; String referenceValue = setting.getReferenceValue(); if (referenceValue != null) { try { refNumber = singleValue(elevationParser.parse(referenceValue), new Date()); } catch (ParseException e) { throw new ServiceException( "Unable to parse elevation dimension default value reference '" + referenceValue + "' as long or double", e); } } else { throw new ServiceException( "No reference value given for elevation dimension default value 'fixed' strategy"); } retval = fixedValueStrategyFactory.createFixedValueStrategy(refNumber, referenceValue); break; } } return retval; } private Object singleValue(Collection parsed, Object defaultValue) { Object result = null; if(parsed.size() == 1) { result = parsed.iterator().next(); } else if(parsed.size() > 1) { throw new IllegalArgumentException("Dimension reference value must be a single value or range"); } if(result == null) { return defaultValue; } else { return result; } } private DimensionDefaultValueSelectionStrategy getDefaultCustomDimensionStrategy(ResourceInfo resource, DimensionDefaultValueSetting setting) { DimensionDefaultValueSelectionStrategy retval = null; String referenceValue = null; switch (setting.getStrategyType()) { case NEAREST: { Object refValue; referenceValue = setting.getReferenceValue(); if (referenceValue != null) { try { refValue = new Date(DateUtil.parseDateTime(referenceValue)); } catch (IllegalArgumentException e) { try { refValue = Long.parseLong(referenceValue); } catch (NumberFormatException nfe) { try { refValue = Double.parseDouble(referenceValue); } catch (NumberFormatException nfe2) { refValue = referenceValue; } } } if (resource instanceof FeatureTypeInfo) { retval = featureNearestValueStrategyFactory .createNearestValueStrategy(refValue); } else if (resource instanceof CoverageInfo) { retval = coverageNearestValueStrategyFactory .createNearestValueStrategy(refValue); } } else { throw new ServiceException( "No reference value given for custom dimension default value 'nearest' strategy"); } break; } case MINIMUM: { if (resource instanceof FeatureTypeInfo) { retval = featureCustomDimensionMinimumStrategy; } else if (resource instanceof CoverageInfo) { retval = coverageCustomDimensionMinimumStrategy; } break; } case MAXIMUM: { if (resource instanceof FeatureTypeInfo) { retval = featureCustomDimensionMaximumStrategy; } else if (resource instanceof CoverageInfo) { retval = coverageCustomDimensionMaximumStrategy; } break; } case FIXED: { Object refValue; referenceValue = setting.getReferenceValue(); if (referenceValue != null) { try { refValue = new Date(DateUtil.parseDateTime(referenceValue)); } catch (IllegalArgumentException e) { try { refValue = Long.parseLong(referenceValue); } catch (NumberFormatException nfe) { try { refValue = Double.parseDouble(referenceValue); } catch (NumberFormatException nfe2) { refValue = referenceValue; } } } } else { throw new ServiceException( "No reference value given for custom dimension default value 'fixed' strategy"); } retval = fixedValueStrategyFactory.createFixedValueStrategy(refValue); break; } } return retval; } }