Revision: 6390
          http://sourceforge.net/p/jump-pilot/code/6390
Author:   edso
Date:     2020-08-26 16:02:28 +0000 (Wed, 26 Aug 2020)
Log Message:
-----------
reworked FlexDateParser speedup to enable caching selectively per instance
made most of FlexDateParser static to save resources
use FlexDateParser in ViewSchemaPlugin in FlexFeature (if using identical 
schema)
reenable date tests, working again

Modified Paths:
--------------
    core/trunk/ChangeLog
    core/trunk/src/com/vividsolutions/jump/feature/FlexibleFeature.java
    core/trunk/src/com/vividsolutions/jump/util/FlexibleDateParser.java
    
core/trunk/src/com/vividsolutions/jump/workbench/ui/plugin/ViewSchemaPlugIn.java
    core/trunk/src/jumptest/junit/FlexibleDateParserTestCase.java

Modified: core/trunk/ChangeLog
===================================================================
--- core/trunk/ChangeLog        2020-08-26 15:38:32 UTC (rev 6389)
+++ core/trunk/ChangeLog        2020-08-26 16:02:28 UTC (rev 6390)
@@ -4,6 +4,9 @@
 # 3. be concise but convey the change in a way that ordinary users understand
 #<-------------------------------- 80 chars 
---------------------------------->#
 
+2020-08-26 ede
+  * reworked FlexDateParser speedup to enable caching selectively
+
 2020-08-23 mmichaud <m.michael.mich...@orange.fr>
   * improved component layout of ConnectionDescriptorPanel
 

Modified: core/trunk/src/com/vividsolutions/jump/feature/FlexibleFeature.java
===================================================================
--- core/trunk/src/com/vividsolutions/jump/feature/FlexibleFeature.java 
2020-08-26 15:38:32 UTC (rev 6389)
+++ core/trunk/src/com/vividsolutions/jump/feature/FlexibleFeature.java 
2020-08-26 16:02:28 UTC (rev 6390)
@@ -16,7 +16,7 @@
 
 /**
  * a FlexibleFeature based on {@link BasicFeature} originally used by the
- * GeoJSON reader. currently adding 
+ * GeoJSON reader. currently adding this functionality
  * - "autoextends" by returning null for undefined attribs
  * - lazy conversion of attributes (see {@link #getAttribute(int)})
  *   currently String, Date, Time, Timestamp
@@ -23,6 +23,7 @@
  */
 public class FlexibleFeature extends BasicFeature {
   //private static HashMap<FeatureSchema,FlexibleFeatureSchema> oldToFlexMap = 
new HashMap();
+  private static HashMap<FeatureSchema,FlexibleDateParser> 
schemaToFlexDateParser = new HashMap();
 
   public FlexibleFeature(FeatureSchema featureSchema) {
     super(featureSchema);
@@ -62,8 +63,7 @@
       Date d = parse(attrib);
       if (d!=null){
         attrib = new java.sql.Date(d.getTime());
-        // update the attribute object, so the conversion does not happen on
-        // every getAttrib()
+        // memorize conversion for future getAttrib() calls
         setAttribute(i, attrib);
       } else {
         attrib = null;
@@ -106,8 +106,13 @@
       d = (java.util.Date) dateObject;
     else {
       try {
-        //FlexibleDateParser.getDefaultInstance().setVerbose(true);
-        d = 
FlexibleDateParser.getDefaultInstance().parse(dateObject.toString(), true);
+        // use the same FlexibleDateParser for all Features of this collection
+        if ( !schemaToFlexDateParser.containsKey(getSchema()) ) {
+          FlexibleDateParser fdp = new FlexibleDateParser();
+          fdp.cachingEnabled(true);
+          schemaToFlexDateParser.put(getSchema(), fdp);
+        }
+        d = 
schemaToFlexDateParser.get(getSchema()).parse(dateObject.toString(), false);
       } catch (ParseException e) {
         // TODO: we should find a way to tell the user
         e.printStackTrace();

Modified: core/trunk/src/com/vividsolutions/jump/util/FlexibleDateParser.java
===================================================================
--- core/trunk/src/com/vividsolutions/jump/util/FlexibleDateParser.java 
2020-08-26 15:38:32 UTC (rev 6389)
+++ core/trunk/src/com/vividsolutions/jump/util/FlexibleDateParser.java 
2020-08-26 16:02:28 UTC (rev 6390)
@@ -60,11 +60,45 @@
  * in FlexibleDateParser.txt).
  */
 public class FlexibleDateParser {
-    private static FlexibleDateParser instance = null;
-
     private static List<SimpleDateFormat> lenientFormatters = null;
     private static List<SimpleDateFormat> unlenientFormatters = null;
 
+    // instance variable set via enableCache()
+    private LinkedList<SimpleDateFormat> formattersCache = null;
+
+    public void setVerbose(boolean b) {
+      verbose = b;
+    }
+
+    public void cachingEnabled( boolean onOff ) {
+      if ( onOff != true && formattersCache != null )
+        formattersCache = null;
+      else if ( onOff == true && formattersCache == null )
+        formattersCache = new LinkedList<>();
+    }
+
+    /**
+     * @return null if s is empty
+     */
+    public Date parse(String s, boolean lenient) throws ParseException {
+        if (s.trim().length() == 0) {
+            return null;
+        }
+
+        // try unlenient
+        try {
+            return parse(s, unlenientFormatters());
+        }
+        // try lenient formatters (if enabled)
+        catch (ParseException e) {
+            if (lenient) {
+                return parse(s, lenientFormatters());
+            }
+
+            throw e;
+        }
+    }
+
     //CellEditor used to be a static field CELL_EDITOR, but I was getting
     //problems calling it from ESETextField (it simply didn't appear).
     //The problems vanished when I turned it into a static class. I didn't
@@ -72,6 +106,7 @@
     public static final class CellEditor extends DefaultCellEditor {
         private Object value;
         DateFormat formatter;
+        private FlexibleDateParser flexParser = new FlexibleDateParser();
 
         public CellEditor(DateFormat formatter) {
             super(new JTextField());
@@ -90,7 +125,7 @@
                 try {
                   this.value = formatter.parse(newValue);
                 } catch(ParseException e1) {
-                  this.value = 
FlexibleDateParser.getDefaultInstance().parse(newValue, true);
+                  this.value = flexParser.parse(newValue, true);
                 }
             } catch (Exception e) {
                 // red alert ;) please try again
@@ -148,7 +183,7 @@
 
     private boolean verbose = false;
 
-    private Collection<DatePattern> sortByComplexity(Collection<DatePattern> 
patterns) {
+    private static Collection<DatePattern> 
sortByComplexity(Collection<DatePattern> patterns) {
         //Least complex to most complex. [Jon Aquino]
         TreeSet<DatePattern> sortedPatterns = new TreeSet<>(new 
Comparator<DatePattern>() {
             public int compare(DatePattern o1, DatePattern o2) {
@@ -195,34 +230,29 @@
         return unlenientFormatters;
     }
 
-    /**
-     * @return null if s is empty
-     */
-    public Date parse(String s, boolean lenient) throws ParseException {
-        if (s.trim().length() == 0) {
-            return null;
-        }
-        //The deprecated Date#parse method is actually pretty flexible. [Jon 
Aquino]
-        // [mmichaud 2012-03-17] Date parse without taking Locale into account
-        // -> prefer parse method using localized formatters
-        //try {
-        //    if (verbose) {
-        //        System.out.println(s + " -- Date constructor");
-        //    }
-        //    return new Date(s);
-        //} catch (Exception e) {
-        //    //Eat it. [Jon Aquino]
-        //}
+    private class CompositeList<E> extends AbstractList<E> {
 
-        try {
-            return parse(s, unlenientFormatters());
-        } catch (ParseException e) {
-            if (lenient) {
-                return parse(s, lenientFormatters());
-            }
+      private final List<E> list1;
+      private final List<E> list2;
 
-            throw e;
-        }
+      public CompositeList(List<E> list1, List<E> list2) {
+          List<E> empty = Collections.emptyList();
+          this.list1 = list1 == null ? empty : list1;
+          this.list2 = list2 == null ? empty : list2;
+      }
+
+      @Override
+      public E get(int index) {
+          if (index < list1.size()) {
+              return list1.get(index);
+          }
+          return list2.get(index-list1.size());
+      }
+
+      @Override
+      public int size() {
+          return list1.size() + list2.size();
+      }
     }
 
     private Date parse(String s, List<SimpleDateFormat> formatters) throws 
ParseException {
@@ -229,7 +259,7 @@
         ParseException firstParseException = null;
 
         int i = 0;
-        for (SimpleDateFormat formatter : formatters) {
+        for (SimpleDateFormat formatter : new CompositeList<>(formattersCache, 
formatters)) {
             i++;
             if (verbose || Logger.isTraceEnabled()) {
                 String msg = s
@@ -243,15 +273,19 @@
 
             try {
               Date d = parse(s, formatter);
-              
-              // [ede] 2020-08
-              // moving successful parser to the list's beginning assuming 
-              // that whatever datestring is parsed next will probably be 
-              // in the same format speeding up parsing by magnitudes
-              if (i > 1) {
-                int index = formatters.indexOf(formatter);
-                formatters.remove(index);
-                formatters.add(0, formatter);
+
+              if (formattersCache != null ) {
+                // [ede] 2020-08
+                // adding successful parser to the cache's beginning assuming 
+                // that whatever datestring is parsed next will probably be 
+                // in the same format speeding up parsing by magnitudes
+                int pos = formattersCache.indexOf(formatter);
+                if (pos != 0) {
+                  // remove old entries
+                  formattersCache.removeAll(Collections.singleton(formatter));
+                  // add to beginning
+                  formattersCache.addFirst(formatter);
+                }
               }
 
               return d;
@@ -307,7 +341,7 @@
         }
     }
 
-    public FlexibleDateParser setLocale(Locale locale) {
+    public static void setLocale(Locale locale) {
         Locale defaultLocale = Locale.getDefault();
         Locale.setDefault(locale);
         lenientFormatters = null;
@@ -314,10 +348,9 @@
         unlenientFormatters = null;
         load();
         Locale.setDefault(defaultLocale);
-        return this;
     }
 
-    private void load() {
+    private static void load() {
         if (lenientFormatters == null) {
             // Does not use 18N to be able to reload another language file 
dynamically
             // (with 18N, things seems to be started only once at the start of 
the application)
@@ -324,7 +357,7 @@
             ResourceBundle resourceBundle = 
ResourceBundle.getBundle("language/jump");
 
             try (InputStream inputStream =
-                         
getClass().getResourceAsStream(resourceBundle.getString(
+                         
FlexibleDateParser.class.getResourceAsStream(resourceBundle.getString(
                                  
"com.vividsolutions.jump.util.FlexibleDateParser")
                          )) {
                 Collection<DatePattern> patterns = new ArrayList<>();
@@ -337,8 +370,8 @@
                     }
 
                 }
-                unlenientFormatters = toFormatters(false, patterns);
-                lenientFormatters = toFormatters(true, patterns);
+                unlenientFormatters = 
Collections.unmodifiableList(toFormatters(false, patterns));
+                lenientFormatters = 
Collections.unmodifiableList(toFormatters(true, patterns));
             } catch (IOException e) {
                 Assert.shouldNeverReachHere(e.toString());
             }
@@ -345,7 +378,7 @@
         }
     }
 
-    private List<SimpleDateFormat> toFormatters(boolean lenient, 
Collection<DatePattern> patterns) {
+    private static List<SimpleDateFormat> toFormatters(boolean lenient, 
Collection<DatePattern> patterns) {
         List<SimpleDateFormat> formatters = new ArrayList<>();
         //Sort from least complex to most complex; otherwise, ddMMMyyyy 
         //instead of MMMd will match "May 15". [Jon Aquino]
@@ -357,16 +390,6 @@
         return formatters;
     }
 
-    public void setVerbose(boolean b) {
-        verbose = b;
-    }
-
-    public static FlexibleDateParser getDefaultInstance() {
-      if (instance == null)
-        instance = new FlexibleDateParser();
-      return instance;
-    }
-
     public static void main(String[] args) throws Exception {
       FlexibleDateParser fdp = new FlexibleDateParser();
       fdp.setVerbose(true);

Modified: 
core/trunk/src/com/vividsolutions/jump/workbench/ui/plugin/ViewSchemaPlugIn.java
===================================================================
--- 
core/trunk/src/com/vividsolutions/jump/workbench/ui/plugin/ViewSchemaPlugIn.java
    2020-08-26 15:38:32 UTC (rev 6389)
+++ 
core/trunk/src/com/vividsolutions/jump/workbench/ui/plugin/ViewSchemaPlugIn.java
    2020-08-26 16:02:28 UTC (rev 6390)
@@ -80,8 +80,9 @@
     private EditingPlugIn editingPlugIn;
     private GeometryFactory factory = new GeometryFactory();
     private WKTReader wktReader = new WKTReader(factory);
-    private FlexibleDateParser dateParser = new FlexibleDateParser();
+
     private DateFormat dateFormatter = DateFormat.getDateInstance();
+    private FlexibleDateParser fdp;
 
     private static final String P_LAYER_NAME = "LayerName";
     private static final String P_SCHEMA_MAPPING = "SchemaMapping";
@@ -161,6 +162,8 @@
 
         //Two-phase commit. 
         //Phase 1: check that no conversion errors occur. [Jon Aquino]
+        fdp = new FlexibleDateParser();
+        fdp.cachingEnabled(true);
         for (Iterator i = layer.getFeatureCollectionWrapper().iterator();
                 i.hasNext();) {
             Feature feature = (Feature) i.next();
@@ -250,6 +253,8 @@
 
         //Two-phase commit.
         //Phase 1: check that no conversion errors occur. [Jon Aquino]
+        fdp = new FlexibleDateParser();
+        fdp.cachingEnabled(true);
         for (Iterator i = layer.getFeatureCollectionWrapper().iterator();
              i.hasNext();) {
             Feature feature = (Feature) i.next();
@@ -403,7 +408,7 @@
             }
         } else if (toType == AttributeType.DATE) {
             try {
-                return dateParser.parse(from, false);
+                return fdp.parse(from, false);
             } catch (java.text.ParseException e) {
                 if (forcingInvalidConversionsToNull) return null;
                 throw conversionException("date", from, attributeName);

Modified: core/trunk/src/jumptest/junit/FlexibleDateParserTestCase.java
===================================================================
--- core/trunk/src/jumptest/junit/FlexibleDateParserTestCase.java       
2020-08-26 15:38:32 UTC (rev 6389)
+++ core/trunk/src/jumptest/junit/FlexibleDateParserTestCase.java       
2020-08-26 16:02:28 UTC (rev 6390)
@@ -80,18 +80,12 @@
         //    parser.parse("Jan 06 17:01:02 PST 2003", false));
         assertEquals(simpleFormat1.parse("1970-06-01"),
             parser.parse("Jun 1970", false));
-        // The following test does not pass anymore because from
-        // r6381 the last used parser (here MMM yyyy) is tested first,
-        // and in this case, interpret 19 as the year 19.
-        //assertEquals(simpleFormat1.parse(year + "-06-19"),
-        //    parser.parse("Jun 19", false));
+        assertEquals(simpleFormat1.parse(year + "-06-19"),
+            parser.parse("Jun 19", false));
         assertEquals(simpleFormat1.parse("1970-06-01"),
             parser.parse("June 1970", false));
-        // The following test does not pass anymore because from
-        // r6381 the last used parser (here MMM yyyy) is tested first,
-        // and in this case, interpret 19 as the year 19.
-        //assertEquals(simpleFormat1.parse(year + "-06-19"),
-        //    parser.parse("June 19", false));
+        assertEquals(simpleFormat1.parse(year + "-06-19"),
+            parser.parse("June 19", false));
         assertEquals(simpleFormat1.parse("2003-09-19"),
             parser.parse("Sep 19, 2003", false));
 



_______________________________________________
Jump-pilot-devel mailing list
Jump-pilot-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel

Reply via email to