| After successful execution of WPS processes the Geoserver Process status log in the UI fill up. No entries are ever deleted due to a date parsing error. errors from geoserver log: 2017-02-21 11:33:01,253 DEBUG [geoserver.wps] - Removing statuses matching [[[ NOT [ completionTime IS NULL ] ] AND org.geotools.filter.temporal.BeforeImpl@1139a6ba] AND [[ NOT [ lastUpdated IS NULL ] ] AND org.geotools.filter.temporal.BeforeImpl@c3551a6]] 2017-02-21 11:33:01,253 DEBUG [geotools.util] - InterpolationConverterFactory can be applied from Strings to Interpolation only. 2017-02-21 11:33:01,253 DEBUG [geotools.util] - CRSConverterFactory can be applied from Strings to CRS only. 2017-02-21 11:33:01,253 DEBUG [geotools.util] - InterpolationConverterFactory can be applied from Strings to Interpolation only. 2017-02-21 11:33:01,253 DEBUG [geotools.util] - CRSConverterFactory can be applied from Strings to CRS only. 2017-02-21 11:33:01,253 DEBUG [geotools.util] - InterpolationConverterFactory can be applied from Strings to Interpolation only. 2017-02-21 11:33:01,253 DEBUG [geotools.util] - CRSConverterFactory can be applied from Strings to CRS only. 2017-02-21 11:33:01,253 TRACE [geotools.util] - Error applying the converter class org.geotools.xml.XmlConverterFactory$XmlConverter on (Tue Feb 21 11:23:03 CET 2017,class java.util.Date) java.lang.IllegalArgumentException: Failed to parse time Tue Feb 21 11:23:03 CET 2017 at:Tue Feb 21 11:23:03 CET 2017 at org.geotools.xml.impl.DatatypeConverterImpl.parseTime(DatatypeConverterImpl.java:189) at org.geotools.xml.XmlConverterFactory$XmlConverter.convertFromString(XmlConverterFactory.java:123) at org.geotools.xml.XmlConverterFactory$XmlConverter.convert(XmlConverterFactory.java:76) at org.geotools.util.Converters.convert(Converters.java:168) at org.geotools.util.Converters.convert(Converters.java:129) at org.geotools.temporal.TemporalConverterFactory$2.convert(TemporalConverterFactory.java:51) at org.geotools.util.Converters.convert(Converters.java:168) at org.geotools.util.Converters.convert(Converters.java:129) at org.geoserver.wps.property.BeanPropertyAccessor.get(BeanPropertyAccessor.java:37) at org.geotools.filter.AttributeExpressionImpl.tryAccessor(AttributeExpressionImpl.java:248) at org.geotools.filter.AttributeExpressionImpl.evaluate(AttributeExpressionImpl.java:208) at org.geotools.filter.temporal.BinaryTemporalOperatorImpl.toInstant(BinaryTemporalOperatorImpl.java:64) at org.geotools.filter.temporal.BinaryTemporalOperatorImpl.toTemporal(BinaryTemporalOperatorImpl.java:77) at org.geotools.filter.temporal.BinaryTemporalOperatorImpl.evaluate(BinaryTemporalOperatorImpl.java:52) at org.geotools.filter.AndImpl.evaluate(AndImpl.java:44) at org.geotools.filter.AndImpl.evaluate(AndImpl.java:44) at org.geoserver.wps.MemoryProcessStatusStore.remove(MemoryProcessStatusStore.java:74) at org.geoserver.wps.executor.ProcessStatusTracker.cleanExpiredStatuses(ProcessStatusTracker.java:135) at org.geoserver.wps.WPSStorageCleaner.run(WPSStorageCleaner.java:50) at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) at java.util.concurrent.FutureTask.runAndReset(Unknown Source) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Unknown Source) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) 2017-02-21 11:33:01,253 DEBUG [geotools.util] - InterpolationConverterFactory can be applied from Strings to Interpolation only. 2017-02-21 11:33:01,253 DEBUG [geotools.util] - CRSConverterFactory can be applied from Strings to CRS only. 2017-02-21 11:33:01,253 DEBUG [geotools.util] - InterpolationConverterFactory can be applied from Strings to Interpolation only. 2017-02-21 11:33:01,253 DEBUG [geotools.util] - CRSConverterFactory can be applied from Strings to CRS only. I wonder if this ever worked with java 8, but maybe I'm missing something. Below are some research from the code base: According to the API doc for java 8 for java.util.Date public String toString() Converts this Date object to a String of the form: dow mon dd hh:mm:ss zzz yyyy This comment from the source below clearly states that a date string on the form: dow mon dd hh:mm:ss zzz yyyy would never be parsed correctly by this method geotools/modules/extension/xsd/xsd-core/src/main/java/org/geotools/xml/impl/DatatypeConverterImpl.java /** <p>Parses the lexical representation of the given dateTime value
- and converts it into an instance of {@link java.util.Calendar}.
* Valid lexical representations of a dateTime value include * <pre> * YYYY-MM-DDThh:mm:ss * YYYY-MM-DDThh:mm:ss.sss * YYYY-MM-DDThh:mm:ssZ * YYYY-MM-DDThh:mm:ss-01:00 * </pre> * The former examples are all specified in UTC time. The last example * uses a negative offset of one hour to UTC.</p> * @param arg0 The input string being parsed. * @param lenient parameter used for allowing lenient parsing * @return The input string converted into an instance of * {@link java.util.Calendar} .
- @see javax.xml.bind.ParseConversionEvent
*/ public Calendar parseDateTime(String arg0, boolean lenient)
Unknown macro: { XsDateTimeFormat format = new XsDateTimeFormat(); ParsePosition pos = new ParsePosition(0); Calendar cal = (Calendar) format.parseObject(arg0, pos, lenient); if (cal == null) { throw new IllegalArgumentException("Failed to parse dateTime " + arg0 + " at:" + arg0.substring(pos.getErrorIndex())); } return cal; }
If we follow the stacktrace a bit furhter there seems to be an explicit to String cast in the XmlConverter.convert method. geotools/modules/extension/xsd/xsd-core/src/main/java/org/geotools/xml/XmlConverterFactory.java public class XmlConverterFactory implements ConverterFactory { public Converter createConverter(Class source, Class target, Hints hints) { // make sure either source or target is String in order not to step over // TemporalConverterFactory if (String.class.equals(target)) { if (java.util.Date.class.isAssignableFrom(source)
Calendar.class.isAssignableFrom(source)) { return new XmlConverter(); } } else if (String.class.equals(source)) { if (java.util.Date.class.isAssignableFrom(target) || Calendar.class.isAssignableFrom(target)) { return new XmlConverter(); } } return null; } |
static class XmlConverter implements Converter { public Object convert(Object source, Class target) throws Exception { if (String.class.equals(target)) { return convertToString(source); } return convertFromString((String) source, target); } private Object convertFromString(final String source, final Class<?> target) { // don't bother performing conversions if the target types are not dates/times if(!Calendar.class.equals(target) && !Date.class.isAssignableFrom(target)) return null; //JD: this is a bit of a hack but delegate to the // commons converter in case we are executing first. try { Converter converter = new CommonsConverterFactory().createConverter(String.class, target, null); if (converter != null) { Object converted = null; try { converted = converter.convert(source, target); } catch (Exception e) { //ignore } if (converted != null) { return converted; } } } catch(Exception e) { //fall through to jaxb parsing } Calendar date; //try parsing as dateTime try { try { date = DatatypeConverterImpl.getInstance().parseDateTime(source); } catch(Exception e) { //try as just date date = DatatypeConverterImpl.getInstance().parseDate(source); } } catch (Exception e) { //try as just time date = DatatypeConverterImpl.getInstance().parseTime(source); } if (Calendar.class.equals(target)) { return date; } if (Date.class.isAssignableFrom(target)) { Date time = date.getTime(); //check for subclasses if (java.sql.Date.class.equals(target)) { return new java.sql.Date(time.getTime()); } if (Time.class.equals(target)) { return new Time(time.getTime()); } if (Timestamp.class.equals(target)) { return new Timestamp(time.getTime()); } return time; } return null; } private String convertToString(Object unconvertedValue) { String textValue = null; if (unconvertedValue instanceof Calendar) { Calendar cal = (Calendar) unconvertedValue; textValue = DatatypeConverterImpl.getInstance().printDateTime(cal); } else if(unconvertedValue instanceof java.sql.Date){ DatatypeConverterImpl converter = DatatypeConverterImpl.getInstance(); Object hint = Hints.getSystemDefault(Hints.LOCAL_DATE_TIME_HANDLING); Calendar cal; if(Boolean.TRUE.equals(hint)) { cal = Calendar.getInstance(); } else { cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); } cal.setTimeInMillis(((java.util.Date) unconvertedValue).getTime()); textValue = converter.printDate(cal); } else if (unconvertedValue instanceof java.util.Date) { Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); cal.setTimeInMillis(((java.util.Date) unconvertedValue).getTime()); DatatypeConverterImpl converter = DatatypeConverterImpl.getInstance(); if (unconvertedValue instanceof java.sql.Time) { textValue = converter.printTime(cal); } else { // java.util.Date and java.sql.TimeStamp textValue = converter.printDateTime(cal); } } return textValue; } } } geotools/modules/library/main/src/main/java/org/geotools/temporal/TemporalConverterFactory.java public class TemporalConverterFactory implements ConverterFactory { static Converter dateToInstant = new Converter() { public <T> T convert(Object source, Class<T> target) throws Exception { return (T) new DefaultInstant(new DefaultPosition((Date)source)); } }; static Converter stringToInstant = new Converter() { public <T> T convert(Object source, Class<T> target) throws Exception { //first go to java.util.Date Date d = Converters.convert(source, Date.class); //then go from date to instant return d != null ? dateToInstant.convert(d, target) : null; } }; public Converter createConverter(Class<?> source, Class<?> target, Hints hints) { if (Instant.class.isAssignableFrom(target)) { if (Date.class.isAssignableFrom(source)) { return dateToInstant; } if (String.class.equals(source)) { return stringToInstant; } } return null; } } geoserver/src/extension/wps/wps-core/src/main/java/org/geoserver/wps/executor/ProcessStatusTracker.java public void cleanExpiredStatuses(long expirationThreshold) { Date date = new Date(expirationThreshold); Not completionTimenotNull = FF.not(FF.isNull(FF.property("completionTime"))); Filter completionTimeExpired = FF.before(FF.property("completionTime"), FF.literal(date)); Filter completionTimeFilter = FF.and(completionTimenotNull, completionTimeExpired); Not lastUpdatedNotNull = FF.not(FF.isNull(FF.property("lastUpdated"))); Filter lastUpdatedExpired = FF.before(FF.property("lastUpdated"), FF.literal(date)); Filter lastUpdatedFilter = FF.and(lastUpdatedNotNull, lastUpdatedExpired); And filter = FF.and(completionTimeFilter, lastUpdatedFilter); store.remove(filter); } geotools/modules/library/main/src/main/java/org/geotools/filter/FilterFactoryImpl.java public Literal literal(Object obj) { try { return new LiteralExpressionImpl(obj); } catch (IllegalFilterException e) { new IllegalArgumentException().initCause(e); } return null; } geotools/modules/library/main/src/main/java/org/geotools/filter/LiteralExpressionImpl.java public LiteralExpressionImpl(Object literal) throws IllegalFilterException { this.setValue(literal); } public final void setValue(Object literal) { this.literal = literal; } public Object getValue() { return literal; } public String toString() { return literal == null ? "NULL" : literal.toString(); } |