Java tutorial
/* * Copyright (c) 2008-2016 Haulmont. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.haulmont.cuba.core.sys.querymacro; import com.google.common.base.Strings; import com.haulmont.cuba.core.global.AppBeans; import com.haulmont.cuba.core.global.Scripting; import com.haulmont.cuba.core.global.TimeSource; import groovy.lang.Binding; import org.apache.commons.lang.time.DateUtils; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @Component("cuba_TimeBetweenQueryMacroHandler") @Scope("prototype") public class TimeBetweenQueryMacroHandler extends AbstractQueryMacroHandler { protected static final Pattern MACRO_PATTERN = Pattern.compile("@between\\s*\\(([^)]+)\\)"); protected static final Pattern PARAM_PATTERN = Pattern.compile("(now)\\s*([\\d\\s+-]*)"); protected static final Pattern QUERY_PARAM_PATTERN = Pattern.compile(":(\\w+)"); protected static final Map<String, Object> units = new HashMap<>(); static { units.put("year", Calendar.YEAR); units.put("month", Calendar.MONTH); units.put("day", Calendar.DAY_OF_MONTH); units.put("hour", Calendar.HOUR_OF_DAY); units.put("minute", Calendar.MINUTE); units.put("second", Calendar.SECOND); } protected Map<String, Object> params = new HashMap<>(); public TimeBetweenQueryMacroHandler() { super(MACRO_PATTERN); } @Override public void setQueryParams(Map<String, Object> namedParameters) { } @Override public Map<String, Object> getParams() { return params; } @Override public String replaceQueryParams(String queryString, Map<String, Object> params) { Matcher matcher = MACRO_PATTERN.matcher(queryString); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String macros = matcher.group(0); macros = replaceParamsInMacros(macros, params); matcher.appendReplacement(sb, macros); } matcher.appendTail(sb); return sb.toString(); } protected String replaceParamsInMacros(String macros, Map<String, Object> params) { Matcher matcher = QUERY_PARAM_PATTERN.matcher(macros); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String paramName = matcher.group(1); if (params.containsKey(paramName)) { matcher.appendReplacement(sb, params.get(paramName).toString()); params.remove(paramName); } } matcher.appendTail(sb); return sb.toString(); } @Override protected String doExpand(String macro) { count++; String[] args = macro.split(","); if (args.length != 4 && args.length != 5) throw new RuntimeException("Invalid macro: " + macro); String field = args[0]; TimeZone timeZone = getTimeZoneFromArgs(args, 4); if (timeZone == null) { timeZone = TimeZone.getDefault(); } String param1 = getParam(args, 1, timeZone); String param2 = getParam(args, 2, timeZone); return String.format("(%s >= :%s and %s < :%s)", field, param1, field, param2); } protected String getParam(String[] args, int idx, TimeZone timeZone) { String arg = args[idx].trim(); String unit = args[3].trim(); Matcher matcher = PARAM_PATTERN.matcher(arg); if (!matcher.find()) throw new RuntimeException("Invalid macro argument: " + arg); int num = 0; try { String expr = matcher.group(2); if (!Strings.isNullOrEmpty(expr)) { Scripting scripting = AppBeans.get(Scripting.class); num = scripting.evaluateGroovy(expr, new Binding()); } } catch (NumberFormatException e) { throw new RuntimeException("Invalid macro argument: " + arg, e); } Date date = computeDate(num, unit, timeZone); String paramName = args[0].trim().replace(".", "_") + "_" + count + "_" + idx; params.put(paramName, date); return paramName; } protected Date computeDate(int num, String unit, TimeZone timeZone) { Calendar cal = Calendar.getInstance(timeZone); cal.setTime(AppBeans.get(TimeSource.class).currentTimestamp()); int calField = getCalendarField(unit); if (num != 0) { cal.add(calField, num); } return DateUtils.truncate(cal, calField).getTime(); } protected int getCalendarField(String unit) { Integer calField = (Integer) units.get(unit.toLowerCase()); if (calField == null) throw new RuntimeException("Invalid macro argument: " + unit); return calField; } }