From cdd12a8a463b5fa30ef094a7bdd47cc85e400efa Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Wed, 16 May 2012 11:09:28 +0000
Subject: [PATCH] SP-39 improve searching with dates and timestamps.

SVN: 25275
---
 .../search/DetailedSearchCriterionWidget.java | 30 ++-----
 .../search/detailed/DetailedQueryBuilder.java | 82 ++++++++++++-------
 .../basic/dto/DetailedSearchCriterion.java    | 16 ++--
 3 files changed, 66 insertions(+), 62 deletions(-)

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/search/DetailedSearchCriterionWidget.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/search/DetailedSearchCriterionWidget.java
index 8f553682fbe..93e1df39657 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/search/DetailedSearchCriterionWidget.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/search/DetailedSearchCriterionWidget.java
@@ -16,7 +16,6 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.search;
 
-import java.util.Date;
 import java.util.List;
 
 import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
@@ -36,7 +35,6 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAs
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.GenericConstants;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.model.DetailedSearchFieldComboModel;
-import ch.systemsx.cisd.openbis.generic.client.web.client.application.renderer.DateRenderer;
 import ch.systemsx.cisd.openbis.generic.shared.basic.AttributeSearchFieldKindProvider;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CompareType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriterion;
@@ -212,33 +210,23 @@ public class DetailedSearchCriterionWidget extends HorizontalPanel
         {
             String aCode = selectedFieldName.getAttributeCode();
 
-            @SuppressWarnings("unused")
-            Date date;
-            try
-            {
-                date = DateRenderer.SHORT_DATE_TIME_FORMAT.parse(selectedValue);
-            } catch (IllegalArgumentException ex)
-            {
-                return new DetailedSearchCriterion(selectedFieldName, selectedValue);
-            }
-
             CompareType compareType;
-            if ("REGISTRATION_DATE_FROM".equals(aCode))
+            if ("REGISTRATION_DATE_UNTIL".equals(aCode))
             {
                 compareType = CompareType.LESS_THAN_OR_EQUAL;
             } else if ("REGISTRATION_DATE".equals(aCode))
             {
                 compareType = CompareType.EQUALS;
-            } else if ("REGISTRATION_DATE_UNTIL".equals(aCode))
+            } else if ("REGISTRATION_DATE_FROM".equals(aCode))
             {
                 compareType = CompareType.MORE_THAN_OR_EQUAL;
-            } else if ("MODIFICATION_DATE_FROM".equals(aCode))
+            } else if ("MODIFICATION_DATE_UNTIL".equals(aCode))
             {
                 compareType = CompareType.LESS_THAN_OR_EQUAL;
             } else if ("MODIFICATION_DATE".equals(aCode))
             {
                 compareType = CompareType.EQUALS;
-            } else if ("MODIFICATION_DATE_UNTIL".equals(aCode))
+            } else if ("MODIFICATION_DATE_FROM".equals(aCode))
             {
                 compareType = CompareType.MORE_THAN_OR_EQUAL;
             } else
@@ -246,7 +234,7 @@ public class DetailedSearchCriterionWidget extends HorizontalPanel
                 return new DetailedSearchCriterion(selectedFieldName, selectedValue);
             }
 
-            return new DetailedSearchCriterion(selectedFieldName, compareType, selectedValue, "+1");
+            return new DetailedSearchCriterion(selectedFieldName, compareType, selectedValue);
 
         }
         return null;
@@ -262,13 +250,7 @@ public class DetailedSearchCriterionWidget extends HorizontalPanel
             return null;
         }
 
-        if (criterion.getValue() == null && criterion.getDate() != null)
-        {
-            return name + " = " + criterion.getDate();
-        } else
-        {
-            return name + " = " + criterion.getValue();
-        }
+        return name + " = " + criterion.getValue();
     }
 
     public List<PropertyType> getAvailablePropertyTypes()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/DetailedQueryBuilder.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/DetailedQueryBuilder.java
index 3eacebee33c..536405139fc 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/DetailedQueryBuilder.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/DetailedQueryBuilder.java
@@ -57,6 +57,9 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SearchFieldConstant
  */
 public class DetailedQueryBuilder
 {
+    private static final String[] DATE_FORMATS =
+        { "y-M-d HH:mm:ss", "y-M-d HH:mm", "y-M-d" };
+
     private final static Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
             DetailedQueryBuilder.class);
 
@@ -106,35 +109,8 @@ public class DetailedQueryBuilder
                 resultQuery.add(luceneQuery, occureCondition);
             } else
             {
-                String tzs = criterion.getTimeZone();
-                if (tzs.startsWith("+"))
-                {
-                    tzs = tzs.substring(1);
-                } else if (tzs.equals("Z"))
-                {
-                    tzs = "0";
-                }
-
-                int offset;
-                try
-                {
-                    offset = (-Integer.parseInt(tzs) * 3600000);
-                } catch (NumberFormatException e)
-                {
-                    offset = 0;
-                }
-
-                SimpleDateFormat sdf = new SimpleDateFormat("y-M-d");
-                sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
-
-                Date lower;
-                try
-                {
-                    lower = sdf.parse(criterion.getDate());
-                } catch (ParseException ex)
-                {
-                    throw new IllegalArgumentException(criterion.getDate(), ex);
-                }
+                Date lower = parseDate(criterion.getValue());
+                int offset = getTimeZoneOffset(criterion, lower);
 
                 lower.setTime(lower.getTime() + offset);
                 Date upper = new Date(lower.getTime() + 24 * 3600 * 1000);
@@ -152,7 +128,7 @@ public class DetailedQueryBuilder
                 }
 
                 String fieldName = fieldNames.get(0);
-                DateBridge bridge = new DateBridge(Resolution.HOUR);
+                DateBridge bridge = new DateBridge(Resolution.SECOND);
                 TermRangeQuery q =
                         new TermRangeQuery(fieldName, bridge.objectToString(lower),
                                 bridge.objectToString(upper), true, true);
@@ -169,6 +145,52 @@ public class DetailedQueryBuilder
         return resultQuery;
     }
 
+    private int getTimeZoneOffset(DetailedSearchCriterion criterion, Date lower)
+    {
+        String tzs = criterion.getTimeZone();
+        if (tzs.equals(DetailedSearchCriterion.SERVER_TIMEZONE))
+        {
+            return -TimeZone.getDefault().getOffset(lower.getTime());
+        }
+
+        if (tzs.startsWith("+"))
+        {
+            tzs = tzs.substring(1);
+        } else if (tzs.equals("Z"))
+        {
+            tzs = "0";
+        }
+
+        int offset;
+        try
+        {
+            offset = (int) (-Double.parseDouble(tzs) * 3600000);
+        } catch (NumberFormatException e)
+        {
+            offset = 0;
+        }
+        return offset;
+    }
+
+    private Date parseDate(String dateAsString)
+    {
+        for (String format : DATE_FORMATS)
+        {
+            SimpleDateFormat sdf = new SimpleDateFormat(format);
+            sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
+
+            try
+            {
+                return sdf.parse(dateAsString);
+            } catch (ParseException ex)
+            {
+                // ignore, try next format
+            }
+        }
+        throw new UserFailureException("Couldn't parse date '" + dateAsString
+                + "'. It has to match one of the following formats: " + Arrays.asList(DATE_FORMATS));
+    }
+
     private List<String> extractAssociationPatterns(DetailedSearchAssociationCriteria association)
     {
         List<String> result = new ArrayList<String>();
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/DetailedSearchCriterion.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/DetailedSearchCriterion.java
index 71397535c94..202359fde8a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/DetailedSearchCriterion.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/DetailedSearchCriterion.java
@@ -26,14 +26,14 @@ public class DetailedSearchCriterion implements Serializable
 {
     private static final long serialVersionUID = ServiceVersionHolder.VERSION;
 
+    public static final String SERVER_TIMEZONE = "server";
+
     private DetailedSearchField field;
 
     private CompareType type;
 
     private String value;
 
-    private String date;
-
     private String timezone;
 
     public DetailedSearchCriterion()
@@ -48,11 +48,16 @@ public class DetailedSearchCriterion implements Serializable
         this.type = CompareType.EQUALS;
     }
 
+    public DetailedSearchCriterion(DetailedSearchField field, CompareType type, String date)
+    {
+        this(field, type, date, SERVER_TIMEZONE);
+    }
+
     public DetailedSearchCriterion(DetailedSearchField field, CompareType type, String date,
             String timezone)
     {
         this.field = field;
-        this.date = date;
+        this.value = date;
         this.type = type;
         this.timezone = timezone;
     }
@@ -82,11 +87,6 @@ public class DetailedSearchCriterion implements Serializable
         return this.type;
     }
 
-    public String getDate()
-    {
-        return this.date;
-    }
-
     public String getTimeZone()
     {
         return this.timezone;
-- 
GitLab