1 16 package org.outerj.daisy.query.model.functions; 17 18 import org.outerj.daisy.query.model.AbstractFunction; 19 import org.outerj.daisy.query.model.ValueExpr; 20 import org.outerj.daisy.query.model.QValueType; 21 import org.outerj.daisy.query.model.SqlGenerationContext; 22 import org.outerj.daisy.query.QueryContext; 23 import org.outerj.daisy.repository.query.QueryException; 24 import org.outerj.daisy.repository.query.EvaluationContext; 25 import org.outerj.daisy.repository.Document; 26 import org.outerj.daisy.repository.Version; 27 28 import java.util.*; 29 import java.util.regex.Pattern ; 30 import java.util.regex.Matcher ; 31 import java.sql.PreparedStatement ; 32 import java.sql.SQLException ; 33 34 35 public class RelativeDateTimeFunction extends AbstractFunction { 36 public static final String NAME = "RelativeDateTime"; 37 38 public String getFunctionName() { 39 return NAME; 40 } 41 42 public void prepare(QueryContext context) throws QueryException { 43 super.prepare(context); 44 if (params.size() != 1) 45 throw new QueryException(getFunctionName() + " takes exactly 1 parameter."); 46 47 ValueExpr param = getParam(0); 48 if ((param.getValueType() != QValueType.STRING && param.getValueType() != QValueType.UNDEFINED) 49 || param.isMultiValue() || param.isSymbolicIdentifier()) 50 throw new QueryException("Invalid argument for " + getFunctionName() + " function: " + param.getExpression()); 51 } 52 53 public void generateSqlValueExpr(StringBuffer sql, SqlGenerationContext context) throws QueryException { 54 sql.append(" ? "); 55 } 56 57 public int bindValueExpr(PreparedStatement stmt, int bindPos, QValueType valueType, EvaluationContext evaluationContext) throws SQLException , QueryException { 58 stmt.setDate(bindPos, new java.sql.Date (((Date)evaluate(null, evaluationContext)).getTime())); 59 return ++bindPos; 60 } 61 62 public Object evaluate(QValueType valueType, EvaluationContext evaluationContext) throws QueryException { 63 return getDate((String )getParam(0).evaluate(QValueType.STRING, evaluationContext)); 64 } 65 66 public Object evaluate(QValueType valueType, Document document, Version version, EvaluationContext evaluationContext) throws QueryException { 67 return getDate((String )getParam(0).evaluate(QValueType.STRING, document, version, evaluationContext)); 68 } 69 70 public QValueType getValueType() { 71 return QValueType.DATETIME; 72 } 73 74 public String getTitle(Locale locale) { 75 return getExpression(); 76 } 77 78 public QValueType getOutputValueType() { 79 return QValueType.DATETIME; 80 } 81 82 public Object getOutputValue(Document document, Version version, EvaluationContext evaluationContext) throws QueryException { 83 return evaluate(null, document, version, evaluationContext); 84 } 85 86 87 private Date getDate(String spec) throws QueryException { 88 Pattern pattern = Pattern.compile("^([a-z]+)\\s([a-z]+)\\s([a-z]+)$"); 89 Matcher matcher = pattern.matcher(spec); 90 if (matcher.matches()) { 91 String startOrEnd = matcher.group(1); 93 boolean start; 94 if (startOrEnd.equals("start")) 95 start = true; 96 else if (startOrEnd.equals("end")) 97 start = false; 98 else 99 throw new QueryException(getFunctionName() + " function: first part of expression should be 'start' or 'end', but got " + startOrEnd); 100 101 String shiftParam = matcher.group(2); 103 int shift; 104 if (shiftParam.equals("this")) 105 shift = 0; 106 else if (shiftParam.equals("next")) 107 shift = 1; 108 else if (shiftParam.equals("last")) 109 shift = -1; 110 else 111 throw new QueryException(getFunctionName() + " function: second part of expression should be 'this', 'next' or 'last', but got " + shiftParam); 112 113 String unitParam = matcher.group(3); 115 int shiftUnit; 116 int dayInShiftUnit; 117 if (unitParam.equals("week")) { 118 shiftUnit = Calendar.WEEK_OF_YEAR; 119 dayInShiftUnit = Calendar.DAY_OF_WEEK; 120 } else if (unitParam.equals("month")) { 121 shiftUnit = Calendar.MONTH; 122 dayInShiftUnit = Calendar.DAY_OF_MONTH; 123 } else if (unitParam.equals("year")) { 124 shiftUnit = Calendar.YEAR; 125 dayInShiftUnit = Calendar.DAY_OF_YEAR; 126 } else { 127 throw new QueryException(getFunctionName() + " function: third part of expression should be 'week', 'month' or 'calendar', but got " + unitParam); 128 } 129 130 return calcDate(start, shift, shiftUnit, dayInShiftUnit).getTime(); 131 } else { 132 throw new QueryException("Invalid specification for " + getFunctionName() + " function: " + spec); 133 } 134 } 135 136 protected Calendar calcDate(boolean start, int shift, int shiftUnit, int dayInShiftUnit) { 137 GregorianCalendar calendar = new GregorianCalendar(); 138 139 if (shift != 0) 140 calendar.roll(shiftUnit, shift); 141 142 if (start) 143 calendar.set(dayInShiftUnit, calendar.getActualMinimum(dayInShiftUnit)); 144 else 145 calendar.set(dayInShiftUnit, calendar.getActualMaximum(dayInShiftUnit)); 146 147 if (start) { 148 calendar.set(Calendar.HOUR_OF_DAY, 0); 149 calendar.set(Calendar.MINUTE, 0); 150 calendar.set(Calendar.SECOND, 0); 151 } else { 152 calendar.set(Calendar.HOUR_OF_DAY, 23); 153 calendar.set(Calendar.MINUTE, 59); 154 calendar.set(Calendar.SECOND, 59); 155 } 156 calendar.set(Calendar.MILLISECOND, 0); 158 159 return calendar; 160 } 161 162 } 163 | Popular Tags |