/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * 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 the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>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.apereo.portal.events.aggr.action; import com.google.common.base.Function; import com.google.common.collect.ImmutableSet; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; 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 org.apereo.portal.events.aggr.AggregationInterval; import org.apereo.portal.events.aggr.BaseAggregationImpl_; import org.apereo.portal.events.aggr.DateDimension; import org.apereo.portal.events.aggr.JpaBaseAggregationDao; import org.apereo.portal.events.aggr.TimeDimension; import org.apereo.portal.events.aggr.dao.jpa.DateDimensionImpl; import org.apereo.portal.events.aggr.dao.jpa.DateDimensionImpl_; import org.apereo.portal.events.aggr.dao.jpa.TimeDimensionImpl; import org.apereo.portal.events.aggr.dao.jpa.TimeDimensionImpl_; import org.apereo.portal.events.aggr.groups.AggregatedGroupMapping; import org.joda.time.DateTime; import org.joda.time.LocalDate; import org.springframework.stereotype.Repository; @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; } }