com.day.cq.search.eval.DateRangePredicateEvaluator Maven / Gradle / Ivy
/*
* Copyright 1997-2008 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.search.eval;
import java.util.Calendar;
import java.util.TimeZone;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.ValueFactory;
import com.day.cq.search.Predicate;
import com.day.cq.search.facets.FacetExtractor;
import com.day.cq.search.facets.buckets.ValueRangeBucket;
import com.day.cq.search.facets.extractors.PredefinedBucketsFacetExtractor;
import com.day.cq.search.impl.util.DateUtil;
import com.day.cq.search.impl.util.InvalidDateException;
import org.apache.felix.scr.annotations.Component;
/**
* Matches JCR DATE properties against a date/time interval. This uses the ISO8601
* format for dates and times (YYYY-MM-DDTHH:mm:ss.SSSZ
) and allows also partial
* representations (eg. YYYY-MM-DD
). Alternatively, the timestamp can be
* provided as number of milliseconds since 1970 (UTC timezone, the unix time format).
*
*
* You can ask for anything between two timestamps, anything newer or older than a given date,
* and also chose between inclusive and open intervals.
*
*
* Supports facet extraction. Will provide buckets "today", "this week", "this month", "last 3 months",
* "this year", "last year" and "earlier than last year".
*
*
* Does not support filtering.
*
*
Name:
* daterange
*
* Properties:
*
* - property
- relative path to a DATE property, for example
jcr:lastModified
* - lowerBound
- lower date bound to check property for, for example
2014-10-01
* - lowerOperation
- ">" (newer, default) or ">=" (at or newer), applies to the lowerBound
* - upperBound
- upper bound to check property for, for example
2014-10-01T12:15:00
* - upperOperation
- "<" (older, default) or "<=" (at or older), applies to the upperBound
* - timeZone
- ID of timezone to use when it's not given as ISO-8601 date string; default is the default timezone of the system
*
*
* @since 5.2
*/
@Component(metatype = false, factory="com.day.cq.search.eval.PredicateEvaluator/daterange")
public class DateRangePredicateEvaluator extends RangePropertyPredicateEvaluator {
public static final String TIME_ZONE = "timeZone";
@Override
public String getXPathExpression(Predicate p, EvaluationContext context) {
return super.getXPathExpression(p.get(PROPERTY),
parseDateString(p.get(LOWER_BOUND), p.get(TIME_ZONE), context.getSession()), p.get(LOWER_OPERATION),
parseDateString(p.get(UPPER_BOUND), p.get(TIME_ZONE), context.getSession()), p.get(UPPER_OPERATION));
}
@Override
public boolean canFilter(Predicate p, EvaluationContext context) {
return false;
}
@Override
public boolean canXpath(Predicate p, EvaluationContext context) {
return true;
}
public static String parseDateString(String dateString, String timeZoneID, Session session) {
if (dateString == null || dateString.length() == 0) {
return null;
}
TimeZone timeZone = null;
if (timeZoneID != null && timeZoneID.length() > 0) {
timeZone = TimeZone.getTimeZone(timeZoneID);
}
try {
// use ValueFactory for round-tripping as defined in JSR-170, section 6.2.6
ValueFactory vf = session.getValueFactory();
Calendar date;
try {
// a) check if the number is a plain long (msec since 1970, unix format)
long msec = Long.parseLong(dateString);
date = vf.createValue(msec).getDate();
} catch (NumberFormatException e) {
// b) else check for ISO 8601 format (eg. "2008-12-16")
try {
// DateUtil provides a relaxed ISO 8601 parser as opposed to the strict parser from JCR in ISO8601.java
date = DateUtil.parseISO8601(dateString, timeZone);
} catch (InvalidDateException e1) {
return "";
}
}
return "xs:dateTime('" + vf.createValue(date).getString() + "')";
} catch (RepositoryException e) {
return "";
}
}
public static final String TODAY = "Today";
public static final String THIS_WEEK = "This Week";
public static final String THIS_MONTH = "This Month";
public static final String LAST_THREE_MONTHS = "Last three months";
public static final String THIS_YEAR = "This Year";
public static final String LAST_YEAR = "Last Year";
public static final String EARLIER_THAN_LAST_YEAR = "Earlier than last year";
@Override
public FacetExtractor getFacetExtractor(Predicate p, EvaluationContext context) {
if (!p.hasNonEmptyValue(PROPERTY)) {
return null;
}
PredefinedBucketsFacetExtractor extractor = new PredefinedBucketsFacetExtractor(p.get(PROPERTY));
DateUtil dates = new DateUtil();
final Calendar endOfToday = dates.getToday();
endOfToday.add(Calendar.HOUR, 24);
// -> today
Predicate predicate = p.clone();
predicate.set(LOWER_BOUND, DateUtil.getISO8601DateNoTime(dates.getToday()));
predicate.set(LOWER_OPERATION, ">=");
predicate.set(UPPER_BOUND, DateUtil.getISO8601DateNoTime(endOfToday));
predicate.set(UPPER_OPERATION, "<=");
extractor.addPredefinedBucket(
new ValueRangeBucket(TODAY, dates.getToday().getTimeInMillis(), true, endOfToday.getTimeInMillis(), true, predicate));
// -> this week
predicate = p.clone();
predicate.set(LOWER_BOUND, DateUtil.getISO8601DateNoTime(dates.getWeekStart()));
predicate.set(LOWER_OPERATION, ">=");
predicate.set(UPPER_BOUND, DateUtil.getISO8601DateNoTime(endOfToday));
predicate.set(UPPER_OPERATION, "<=");
extractor.addPredefinedBucket(
new ValueRangeBucket(THIS_WEEK, dates.getWeekStart().getTimeInMillis(), true, endOfToday.getTimeInMillis(), true, predicate));
// -> this month
predicate = p.clone();
predicate.set(LOWER_BOUND, DateUtil.getISO8601DateNoTime(dates.getMonthStart()));
predicate.set(LOWER_OPERATION, ">=");
predicate.set(UPPER_BOUND, DateUtil.getISO8601DateNoTime(endOfToday));
predicate.set(UPPER_OPERATION, "<=");
extractor.addPredefinedBucket(
new ValueRangeBucket(THIS_MONTH, dates.getMonthStart().getTimeInMillis(), true, endOfToday.getTimeInMillis(), true, predicate));
// -> last three months
predicate = p.clone();
predicate.set(LOWER_BOUND, DateUtil.getISO8601DateNoTime(dates.getThreeMonthsAgo()));
predicate.set(LOWER_OPERATION, ">=");
predicate.set(UPPER_BOUND, DateUtil.getISO8601DateNoTime(endOfToday));
predicate.set(UPPER_OPERATION, "<=");
extractor.addPredefinedBucket(
new ValueRangeBucket(LAST_THREE_MONTHS, dates.getThreeMonthsAgo().getTimeInMillis(), true, endOfToday.getTimeInMillis(), true, predicate));
// -> this year
predicate = p.clone();
predicate.set(LOWER_BOUND, DateUtil.getISO8601DateNoTime(dates.getYearStart()));
predicate.set(LOWER_OPERATION, ">=");
predicate.set(UPPER_BOUND, DateUtil.getISO8601DateNoTime(endOfToday));
predicate.set(UPPER_OPERATION, "<=");
extractor.addPredefinedBucket(
new ValueRangeBucket(THIS_YEAR, dates.getYearStart().getTimeInMillis(), true, endOfToday.getTimeInMillis(), true, predicate));
// -> last year
predicate = p.clone();
predicate.set(LOWER_BOUND, DateUtil.getISO8601DateNoTime(dates.getLastYearStart()));
predicate.set(LOWER_OPERATION, ">=");
predicate.set(UPPER_BOUND, DateUtil.getISO8601DateNoTime(dates.getYearStart()));
predicate.set(UPPER_OPERATION, "<=");
extractor.addPredefinedBucket(
new ValueRangeBucket(LAST_YEAR, dates.getLastYearStart().getTimeInMillis(), true, dates.getYearStart().getTimeInMillis(), true, predicate));
// -> earlier than last year
predicate = p.clone();
predicate.set(LOWER_BOUND, null);
predicate.set(UPPER_BOUND, DateUtil.getISO8601DateNoTime(dates.getLastYearStart()));
predicate.set(UPPER_OPERATION, "<");
extractor.addPredefinedBucket(
new ValueRangeBucket(EARLIER_THAN_LAST_YEAR, // + new SimpleDateFormat("yyyy").format(dates.getLastYearStart().getTime()),
null, true, dates.getLastYearStart().getTimeInMillis(), false, predicate));
return extractor;
}
}