001/**
002 *  '$Author: welker $'
003 *  '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $'
004 *  '$Revision: 24234 $'
005 *
006 *  For Details:
007 *  http://www.kepler-project.org
008 *
009 *  Copyright (c) 2009-2010 The Regents of the
010 *  University of California. All rights reserved. Permission is hereby granted,
011 *  without written agreement and without license or royalty fees, to use, copy,
012 *  modify, and distribute this software and its documentation for any purpose,
013 *  provided that the above copyright notice and the following two paragraphs
014 *  appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF
015 *  CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
016 *  OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
017 *  DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
018 *  POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY
019 *  DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
020 *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
021 *  SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 *  CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 *  ENHANCEMENTS, OR MODIFICATIONS.
024 */
025
026package org.kepler.workflowrunmanager;
027
028import java.sql.Timestamp;
029import java.text.DateFormat;
030import java.text.ParseException;
031import java.util.Date;
032import java.util.regex.Matcher;
033import java.util.regex.Pattern;
034
035public class StartTimeQueryParse {
036
037        private static int numAllowedDates = 2;
038        private String[] parsedDates = new String[numAllowedDates];
039        public Date[] dates = new Date[numAllowedDates];
040        public boolean[] justDateNoTime = new boolean[numAllowedDates];
041        
042        // pattern for one Date
043        private String oneDateRegEx = "\\s*(.*)";
044        // pattern for operator >,< and one Date
045        private String oneDateWithOpRegEx = "([><])\\s*(.*)";
046        // pattern for date range. Date1 - Date2
047        private String dateRangeRegEx = "(.*)\\s*"+WRMDefaults.RANGE_SEPARATOR+"\\s*(.*)";
048
049        private Pattern oneDatePattern = Pattern.compile(oneDateRegEx);
050        private Pattern oneDateWithOpPattern = Pattern.compile(oneDateWithOpRegEx);
051        private Pattern dateRangePattern = Pattern.compile(dateRangeRegEx);
052
053        private boolean isValid = false;
054        private boolean isRange = false;
055        private String operator = null;
056        private int numDates = 0;
057        private String completeText = "";
058        
059        private static final String LESS_THAN = "<";
060        private static final String GREATER_THAN = ">";
061        
062        private static final int NUM_MILLISECONDS_IN_DAY = 86400000;
063        private static final int ONE_MILLISECOND = 1;
064        
065        // FIXME: hardcodes further down require this ordering.
066        public DateFormat[] dateTimeFormats = {
067                        // date format,time format
068                        DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG),
069                        DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.MEDIUM),
070                        DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT),
071                        DateFormat.getDateInstance(DateFormat.LONG),
072                        DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG),
073                        DateFormat
074                                        .getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM),
075                        DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT),
076                        DateFormat.getDateInstance(DateFormat.MEDIUM),
077                        DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG),
078                        DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM),
079                        DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT),
080                        DateFormat.getDateInstance(DateFormat.SHORT), };
081
082        public StartTimeQueryParse(String startTimeQuery) {
083
084                Matcher oneDateMatcher = oneDatePattern.matcher(startTimeQuery);
085                Matcher oneDateWithOpMatcher = oneDateWithOpPattern
086                                .matcher(startTimeQuery);
087                Matcher dateRangeMatcher = dateRangePattern.matcher(startTimeQuery);
088
089                if (dateRangeMatcher.matches()) {
090                        isRange = true;
091                        int successfulParses = 0;
092                        for (int i = 0, j = 1; i < numAllowedDates; i++, j++) {
093                                // parse date or date time
094                                for (int x = 0; x < dateTimeFormats.length; x++) {
095                                        try {
096                                                dates[i] = dateTimeFormats[x].parse(dateRangeMatcher
097                                                                .group(j));
098                                                parsedDates[i] = dateTimeFormats[x].format(dates[i]);
099                                                successfulParses++;
100                                                numDates = getNumItems() + 1;
101                                                if ((x + 1) % 4 == 0) { // TODO fixme, this is nasty
102                                                        justDateNoTime[i] = true;
103                                                }
104                                                break;
105                                        } catch (ParseException pe) {
106                                        }
107                                }
108                                
109                                if (i % 2 == 0) {
110                                        completeText += parsedDates[i] + " "
111                                                        + WRMDefaults.RANGE_SEPARATOR + " ";
112                                } else {
113                                        //comma here if we allow >1 range
114                                        completeText += parsedDates[i];
115                                }
116                                
117                        }
118                        if (successfulParses == numAllowedDates) {
119                                isValid = true;
120                                for (int i = 0; i < numAllowedDates - 1; i++) {
121                                        // make sure received dates are in order
122                                        if (dates[i].compareTo(dates[i + 1]) > 0) {
123                                                isValid = false;
124                                        }
125                                }
126                        } else {
127                                isValid = false;
128                        }
129                } else if (oneDateWithOpMatcher.matches()) {
130                        isRange = false;
131                        operator = oneDateWithOpMatcher.group(1);
132                        numDates = 1;
133
134                        // Parse date or date+time
135                        for (int x = 0; x < dateTimeFormats.length; x++) {
136                                try {
137                                        // TODO fixme hardcode:
138                                        dates[0] = dateTimeFormats[x].parse(oneDateWithOpMatcher
139                                                        .group(2));
140                                        parsedDates[0] = dateTimeFormats[x].format(dates[0]);
141                                        isValid = true;
142                                        if ((x + 1) % 4 == 0) { // TODO fixme, this is nasty
143                                                justDateNoTime[0] = true;
144                                        }
145                                        break;
146                                } catch (ParseException pe) {
147                                }
148                        }
149                        
150                        completeText = operator + " " + parsedDates[0];
151                        
152                } else if (oneDateMatcher.matches()) {
153                        isRange = false;
154                        numDates = 1;
155
156                        // Parse date. For op-less one-date, just allowing date, no time,
157                        // for now at least.
158                        // FIXME more mod 4 nastiness
159                        for (int x = 3; x < dateTimeFormats.length; x += 4) {
160                                try {
161                                        // TODO fixme hardcode:
162                                        dates[0] = dateTimeFormats[x]
163                                                        .parse(oneDateMatcher.group(1));
164                                        parsedDates[0] = dateTimeFormats[x].format(dates[0]);
165                                        isValid = true;
166                                        justDateNoTime[0] = true;
167                                        break;
168                                } catch (ParseException pe) {
169                                }
170                        }
171                        completeText = parsedDates[0];
172                }
173        }
174        
175        public String getCompleteText(){
176                return completeText;
177        }
178        
179        public boolean isValid(){
180                return isValid;
181        }
182        public boolean isRange(){
183                return isRange;
184        }
185        public String getOperator(){
186                return operator;
187        }
188        public int getNumItems(){
189                return numDates;
190        }
191        
192        /**
193         * Returns true if input date passes the filter for this StartTimeQueryParse
194         * @param inputDate
195         * @return
196         */
197        public boolean passesFilter(Date inputDate){
198                if (isValid()){
199                        if (isRange()){
200                                if (inputDate.compareTo(dates[0]) >= 0){
201                                        if (inputDate.compareTo(dates[1]) <= 0){
202                                                return true;
203                                        }
204                                }
205                        }
206                        else{ //Not a range
207                                if (getOperator() != null){
208                                        if (getOperator().equals(GREATER_THAN)){
209                                                if (inputDate.compareTo(dates[0]) > 0){
210                                                        return true;
211                                                }
212                                        }
213                                        else if (getOperator().equals(LESS_THAN)){
214                                                if (inputDate.compareTo(dates[0]) < 0){
215                                                        return true;
216                                                }
217                                        }
218                                }
219                                else{
220                                        Date after = new Date(dates[0].getTime() + ONE_MILLISECOND);
221                                        Date before = new Timestamp(dates[0].getTime()
222                                                        + NUM_MILLISECONDS_IN_DAY - ONE_MILLISECOND);
223                                        if (inputDate.compareTo(after) > 0) {
224                                                if (inputDate.compareTo(before) < 0){
225                                                        return true;
226                                                }
227                                        }
228                                        
229                                }
230                        }
231                }
232                return false;
233        }
234        
235}