/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you 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 org.jasig.portal.events.aggr.action;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableSet;
import org.jasig.portal.events.aggr.AggregationInterval;
import org.jasig.portal.events.aggr.BaseAggregationImpl_;
import org.jasig.portal.events.aggr.DateDimension;
import org.jasig.portal.events.aggr.JpaBaseAggregationDao;
import org.jasig.portal.events.aggr.TimeDimension;
import org.jasig.portal.events.aggr.dao.jpa.DateDimensionImpl;
import org.jasig.portal.events.aggr.dao.jpa.DateDimensionImpl_;
import org.jasig.portal.events.aggr.dao.jpa.TimeDimensionImpl;
import org.jasig.portal.events.aggr.dao.jpa.TimeDimensionImpl_;
import org.jasig.portal.events.aggr.groups.AggregatedGroupMapping;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.springframework.stereotype.Repository;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author Chris Waymire (chris@waymire.net)
*/
@Repository
public class JpaSearchRequestAggregationDao extends
JpaBaseAggregationDao<SearchRequestAggregationImpl, SearchRequestAggregationKey> implements
SearchRequestAggregationPrivateDao {
private ParameterExpression<Set> searchTermParameter;
protected CriteriaQuery<SearchRequestAggregationImpl> findAllSearchRequestAggregationsByDateRangeQuery;
public JpaSearchRequestAggregationDao() {
super(SearchRequestAggregationImpl.class);
}
@Override
protected void createCriteriaQueries() {
this.findAllSearchRequestAggregationsByDateRangeQuery = this.createCriteriaQuery(new Function<CriteriaBuilder, CriteriaQuery<SearchRequestAggregationImpl>>() {
@Override
public CriteriaQuery<SearchRequestAggregationImpl> apply(CriteriaBuilder cb) {
final CriteriaQuery<SearchRequestAggregationImpl> criteriaQuery = cb.createQuery(SearchRequestAggregationImpl.class);
final Root<SearchRequestAggregationImpl> ba = criteriaQuery.from(SearchRequestAggregationImpl.class);
final Join<SearchRequestAggregationImpl, DateDimensionImpl> dd = ba.join(BaseAggregationImpl_.dateDimension, JoinType.LEFT);
final Join<SearchRequestAggregationImpl, TimeDimensionImpl> td = ba.join(BaseAggregationImpl_.timeDimension, JoinType.LEFT);
final List<Predicate> keyPredicates = new ArrayList<Predicate>();
keyPredicates.add(cb.and( //Restrict results by outer date range
cb.greaterThanOrEqualTo(dd.get(DateDimensionImpl_.date), startDate),
cb.lessThan(dd.get(DateDimensionImpl_.date), endPlusOneDate)
));
keyPredicates.add(cb.or( //Restrict start of range by time as well
cb.greaterThan(dd.get(DateDimensionImpl_.date), startDate),
cb.greaterThanOrEqualTo(td.get(TimeDimensionImpl_.time), startTime)
));
keyPredicates.add(cb.or( //Restrict end of range by time as well
cb.lessThan(dd.get(DateDimensionImpl_.date), endDate),
cb.lessThan(td.get(TimeDimensionImpl_.time), endTime)
));
keyPredicates.add(cb.equal(ba.get(BaseAggregationImpl_.interval), intervalParameter));
keyPredicates.add(ba.get(BaseAggregationImpl_.aggregatedGroup).in(aggregatedGroupsParameter));
criteriaQuery.select(ba);
criteriaQuery.where(keyPredicates.toArray(new Predicate[keyPredicates.size()]));
criteriaQuery.orderBy(cb.desc(dd.get(DateDimensionImpl_.date)), cb.desc(td.get(TimeDimensionImpl_.time)));
return criteriaQuery;
}
});
}
@Override
protected void createParameterExpressions() {
this.searchTermParameter = this.createParameterExpression(Set.class,"searchTerm");
}
@Override
protected void addFetches(Root<SearchRequestAggregationImpl> root) {
}
@Override
protected void addUnclosedPredicate(CriteriaBuilder cb, Root<SearchRequestAggregationImpl> root,
List<Predicate> keyPredicates) {
keyPredicates.add(cb.isFalse(root.get(SearchRequestAggregationImpl_.complete)));
}
@Override
protected SearchRequestAggregationImpl createAggregationInstance(SearchRequestAggregationKey key) {
final TimeDimension timeDimension = key.getTimeDimension();
final DateDimension dateDimension = key.getDateDimension();
final AggregationInterval interval = key.getInterval();
final AggregatedGroupMapping aggregatedGroup = key.getAggregatedGroup();
final String searchTerm = key.getSearchTerm();
return new SearchRequestAggregationImpl(timeDimension, dateDimension, interval, aggregatedGroup,searchTerm);
}
@Override
protected SearchRequestAggregationKey getAggregationKey(SearchRequestAggregationImpl instance) {
return instance.getAggregationKey();
}
@Override
protected void bindAggregationSpecificKeyParameters(TypedQuery<SearchRequestAggregationImpl> query,
Set<SearchRequestAggregationKey> keys) {
query.setParameter(this.searchTermParameter,extractSearchTerms(keys));
}
@Override
protected void bindAggregationSpecificKeyParameters(NaturalIdQuery<SearchRequestAggregationImpl> query,
SearchRequestAggregationKey key) {
query.using(SearchRequestAggregationImpl_.searchTerm, key.getSearchTerm());
}
@Override
public final List<SearchRequestAggregationImpl> getAggregations(DateTime start, DateTime end, AggregationInterval interval,
AggregatedGroupMapping aggregatedGroupMapping, AggregatedGroupMapping... aggregatedGroupMappings) {
if (!start.isBefore(end)) {
throw new IllegalArgumentException("Start must be before End: " + start + " - " + end);
}
final LocalDate startDate = start.toLocalDate();
final LocalDate endDate = end.toLocalDate();
final TypedQuery<SearchRequestAggregationImpl> query = this.createQuery(this.findAllSearchRequestAggregationsByDateRangeQuery);
query.setParameter(this.startDate, startDate);
query.setParameter(this.startTime, start.toLocalTime());
query.setParameter(this.endDate, endDate);
query.setParameter(this.endTime, end.toLocalTime());
query.setParameter(this.endPlusOneDate, endDate.plusDays(1));
query.setParameter(this.intervalParameter, interval);
final Set<AggregatedGroupMapping> groups = ImmutableSet.<AggregatedGroupMapping>builder().add(aggregatedGroupMapping).add(aggregatedGroupMappings).build();
query.setParameter(this.aggregatedGroupsParameter, groups);
return query.getResultList();
}
private Set<String> extractSearchTerms(Set<SearchRequestAggregationKey> keys) {
Set<String> searchTerms = new HashSet<String>();
for (SearchRequestAggregationKey key : keys) {
searchTerms.add(key.getSearchTerm());
}
return searchTerms;
}
}