/** * Licensed to The Apereo Foundation under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * * The Apereo Foundation licenses this file to you under the Educational * Community 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://opensource.org/licenses/ecl2.txt * * 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.opencastproject.scheduler.impl.persistence; import static org.opencastproject.util.data.Arrays.array; import static org.opencastproject.util.data.Collections.list; import static org.opencastproject.util.data.Monadics.mlist; import org.opencastproject.metadata.dublincore.DublinCore; import org.opencastproject.metadata.dublincore.DublinCoreCatalog; import org.opencastproject.metadata.dublincore.DublinCoreCatalogService; import org.opencastproject.scheduler.api.SchedulerService.ReviewStatus; import org.opencastproject.scheduler.impl.SchedulerServiceDatabase; import org.opencastproject.scheduler.impl.SchedulerServiceDatabaseException; import org.opencastproject.security.api.AccessControlList; import org.opencastproject.security.api.AccessControlParser; import org.opencastproject.util.NotFoundException; import org.opencastproject.util.data.Function2; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.joda.time.DateTime; import org.joda.time.DateTimeConstants; import org.joda.time.DateTimeFieldType; import org.joda.time.Partial; import org.joda.time.ReadableInstant; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.Properties; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.NoResultException; import javax.persistence.Query; /** * Implements {@link SchedulerServiceDatabase}. */ public class SchedulerServiceDatabaseImpl implements SchedulerServiceDatabase { public static final String PERSISTENCE_UNIT = "org.opencastproject.scheduler.impl.persistence"; /** Logging utilities */ private static final Logger logger = LoggerFactory.getLogger(SchedulerServiceDatabaseImpl.class); /** Factory used to create {@link EntityManager}s for transactions */ protected EntityManagerFactory emf; /** Dublin core service for serializing and deserializing Dublin cores */ protected DublinCoreCatalogService dcService; /** * Creates {@link EntityManagerFactory} using persistence provider and properties passed via OSGi. * * @param cc */ public void activate(ComponentContext cc) { logger.info("Activating persistence manager for scheduler"); } /** OSGi DI */ public void setEntityManagerFactory(EntityManagerFactory emf) { this.emf = emf; } /** * OSGi callback to set dublin core catalog service. * * @param dcService * {@link DublinCoreCatalogService} object */ public void setDublinCoreService(DublinCoreCatalogService dcService) { this.dcService = dcService; } /** * Serializes Dublin core catalog and returns it as String. * * @param dc * {@link DublinCoreCatalog} to be serialized * @return String presenting serialized dublin core * @throws IOException * if serialization fails */ private String serializeDublinCore(DublinCoreCatalog dc) throws IOException { InputStream in = dcService.serialize(dc); StringWriter writer = new StringWriter(); IOUtils.copy(in, writer, "UTF-8"); return writer.toString(); } /** * Serializes Properties and returns them as string. * * @param caProperties * Properties to be serialized * @return String representation of properties * @throws IOException * if serialization fails */ private String serializeProperties(Properties caProperties) throws IOException { StringWriter writer = new StringWriter(); caProperties.store(writer, "Capture Agent specific data"); return writer.toString(); } /** * Parses Dublin core stored as string. * * @param dcXML * string representation of Dublin core * @return parsed {@link DublinCoreCatalog} * @throws IOException * if parsing fails */ private DublinCoreCatalog parseDublinCore(String dcXML) throws IOException { DublinCoreCatalog dc = dcService.load(IOUtils.toInputStream(dcXML, "UTF-8")); return dc; } /** * Parses Properties represented as String. * * @param serializedProperties * @return parsed Properties * @throws IOException * if parsing fails */ private Properties parseProperties(String serializedProperties) throws IOException { Properties caProperties = new Properties(); caProperties.load(new StringReader(serializedProperties)); return caProperties; } @Override public void deleteEvent(long eventId) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; EntityTransaction tx = null; try { em = emf.createEntityManager(); tx = em.getTransaction(); tx.begin(); EventEntity entity = em.find(EventEntity.class, eventId); if (entity == null) { throw new NotFoundException("Event with ID " + eventId + " does not exist"); } em.remove(entity); tx.commit(); } catch (Exception e) { if (tx.isActive()) { tx.rollback(); } if (e instanceof NotFoundException) { throw (NotFoundException) e; } logger.error("Could not delete series: {}", e.getMessage()); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public int countEvents() throws SchedulerServiceDatabaseException { EntityManager em = emf.createEntityManager(); Query query = em.createNamedQuery("Event.countAll"); try { Number total = (Number) query.getSingleResult(); return total.intValue(); } catch (Exception e) { logger.error("Could not find the number of events.", e); throw new SchedulerServiceDatabaseException(e); } finally { em.close(); } } @Override @SuppressWarnings("unchecked") public DublinCoreCatalog[] getAllEvents() throws SchedulerServiceDatabaseException { EntityManager em = null; Query query = null; List<EventEntity> eventEntities = null; try { em = emf.createEntityManager(); query = em.createNamedQuery("Event.findAll"); eventEntities = query.getResultList(); } catch (Exception e) { logger.error("Could not retrieve all events: {}", e.getMessage()); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } List<DublinCoreCatalog> eventList = new LinkedList<DublinCoreCatalog>(); try { for (EventEntity entity : eventEntities) { DublinCoreCatalog dc = parseDublinCore(entity.getEventDublinCore()); eventList.add(dc); } } catch (Exception e) { logger.error("Could not parse event entity: {}", e.getMessage()); throw new SchedulerServiceDatabaseException(e); } return eventList.toArray(new DublinCoreCatalog[eventList.size()]); } @Override public Properties getEventMetadata(long eventId) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); EventEntity entity = em.find(EventEntity.class, eventId); if (entity == null) { throw new NotFoundException("Could not found series with ID " + eventId); } Properties caProperties = null; if (entity.getCaptureAgentMetadata() != null) { caProperties = parseProperties(entity.getCaptureAgentMetadata()); } return caProperties; } catch (NotFoundException e) { throw e; } catch (Exception e) { logger.error("Could not retrieve CA properties for event '{}': {}", eventId, e.getMessage()); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public void updateEvent(DublinCoreCatalog event) throws NotFoundException, SchedulerServiceDatabaseException { if (event == null) { throw new SchedulerServiceDatabaseException("Cannot update <null> event"); } Long eventId = Long.parseLong(event.getFirst(DublinCore.PROPERTY_IDENTIFIER)); String dcXML; try { dcXML = serializeDublinCore(event); } catch (Exception e1) { logger.error("Could not serialize Dublin Core: {}", e1); throw new SchedulerServiceDatabaseException(e1); } EntityManager em = null; EntityTransaction tx = null; try { em = emf.createEntityManager(); tx = em.getTransaction(); tx.begin(); EventEntity entity = em.find(EventEntity.class, eventId); if (entity == null) { throw new NotFoundException("Event with ID " + eventId + " does not exist."); } entity.setEventDublinCore(dcXML); em.merge(entity); tx.commit(); } catch (NotFoundException e) { throw e; } catch (Exception e) { if (tx.isActive()) { tx.rollback(); } logger.error("Could not store event: {}", e.getMessage()); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public void storeEvents(DublinCoreCatalog... events) throws SchedulerServiceDatabaseException { EntityManager em = null; EntityTransaction tx = null; try { em = emf.createEntityManager(); tx = em.getTransaction(); tx.begin(); for (DublinCoreCatalog event : events) { Long eventId = Long.parseLong(event.getFirst(DublinCore.PROPERTY_IDENTIFIER)); String dcXML; try { dcXML = serializeDublinCore(event); } catch (Exception e1) { logger.error("Could not serialize Dublin Core: {}", e1); throw new SchedulerServiceDatabaseException(e1); } EventEntity entity = new EventEntity(); entity.setEventId(eventId); entity.setEventDublinCore(dcXML); em.persist(entity); } tx.commit(); } catch (SchedulerServiceDatabaseException e) { throw e; } catch (Exception e) { if (tx.isActive()) { tx.rollback(); } logger.error("Could not store events: {}", e); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public void updateEventWithMetadata(long eventId, Properties caProperties) throws SchedulerServiceDatabaseException, NotFoundException { if (caProperties == null) { caProperties = new Properties(); } String caSerialized; try { caSerialized = serializeProperties(caProperties); } catch (IOException e) { logger.error("Could not serialize properties: {}", e); throw new SchedulerServiceDatabaseException(e); } EntityManager em = null; EntityTransaction tx = null; try { em = emf.createEntityManager(); tx = em.getTransaction(); tx.begin(); EventEntity entity = em.find(EventEntity.class, eventId); if (entity == null) { throw new NotFoundException("Event with ID: " + eventId + " does not exist"); } entity.setCaptureAgentMetadata(caSerialized); em.merge(entity); tx.commit(); } catch (NotFoundException e) { logger.error("Event with ID '{}' does not exist", eventId); throw e; } catch (Exception e) { if (tx.isActive()) { tx.rollback(); } logger.error("Could not store event metadata: {}", e.getMessage()); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public void updateEventAccessControlList(long eventId, AccessControlList accessControlList) throws NotFoundException, SchedulerServiceDatabaseException { String aclSerialized = null; try { if (accessControlList != null) aclSerialized = AccessControlParser.toJson(accessControlList); } catch (IOException e) { logger.error("Could not serialize access control list: {}", e); throw new SchedulerServiceDatabaseException(e); } EntityManager em = null; EntityTransaction tx = null; try { em = emf.createEntityManager(); tx = em.getTransaction(); tx.begin(); EventEntity event = em.find(EventEntity.class, eventId); if (event == null) throw new NotFoundException("Event " + eventId + " does not exist"); event.setAccessControl(aclSerialized); em.merge(event); tx.commit(); } catch (NotFoundException e) { throw e; } catch (Exception e) { if (tx.isActive()) { tx.rollback(); } logger.error("Could not update the access control list for event '{}': {}", eventId, ExceptionUtils.getStackTrace(e)); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public void updateEventMediaPackageId(long eventId, String mediaPackageId) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; EntityTransaction tx = null; try { em = emf.createEntityManager(); tx = em.getTransaction(); tx.begin(); EventEntity event = em.find(EventEntity.class, eventId); if (event == null) throw new NotFoundException("Event " + eventId + " does not exist"); event.setMediaPackageId(mediaPackageId); em.merge(event); tx.commit(); } catch (NotFoundException e) { throw e; } catch (Exception e) { if (tx.isActive()) { tx.rollback(); } logger.error("Could not update the mediapackage for event '{}': {}", eventId, ExceptionUtils.getStackTrace(e)); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public AccessControlList getAccessControlList(long eventId) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); EventEntity event = em.find(EventEntity.class, eventId); if (event == null) throw new NotFoundException("Event " + eventId + " does not exist"); return event.getAccessControl() != null ? AccessControlParser.parseAcl(event.getAccessControl()) : null; } catch (NotFoundException e) { throw e; } catch (Exception e) { logger.error("Could not retrieve mediapackage for event '{}': {}", eventId, ExceptionUtils.getStackTrace(e)); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public String getMediaPackageId(long eventId) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); EventEntity event = em.find(EventEntity.class, eventId); if (event == null) throw new NotFoundException("Event " + eventId + " does not exist"); return event.getMediaPackageId(); } catch (NotFoundException e) { throw e; } catch (Exception e) { logger.error("Could not retrieve mediapackage for event '{}': {}", eventId, ExceptionUtils.getStackTrace(e)); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public Long getEventId(String mediaPackageId) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); EventEntity event = getEventEntityByMpId(mediaPackageId, em); if (event == null) throw new NotFoundException("Event with MP ID " + mediaPackageId + " does not exist"); return event.getEventId(); } catch (NotFoundException e) { throw e; } catch (Exception e) { logger.error("Could not retrieve event id for event with mediapackage '{}': {}", mediaPackageId, ExceptionUtils.getStackTrace(e)); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public boolean isOptOut(String mediapackageId) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); EventEntity event = getEventEntityByMpId(mediapackageId, em); if (event == null) throw new NotFoundException("Event with MP ID " + mediapackageId + " does not exist"); return event.isOptOut(); } catch (NotFoundException e) { throw e; } catch (Exception e) { logger.error("Could not retrieve review status for event with mediapackage '{}': {}", mediapackageId, ExceptionUtils.getStackTrace(e)); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public boolean isOptOut(Long eventid) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); EventEntity event = em.find(EventEntity.class, eventid); if (event == null) { throw new NotFoundException("Event with ID " + eventid + " does not exist"); } return event.isOptOut(); } catch (NotFoundException e) { throw e; } catch (Exception e) { logger.error("Could not retrieve review status for event with mediapackage '{}': {}", eventid, ExceptionUtils.getStackTrace(e)); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public void updateEventOptOutStatus(String mediapackageId, boolean optOut) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; EntityTransaction tx = null; try { em = emf.createEntityManager(); tx = em.getTransaction(); tx.begin(); EventEntity entity = getEventEntityByMpId(mediapackageId, em); if (entity == null) { throw new NotFoundException("Event with MP ID " + mediapackageId + " does not exist"); } entity.setOptOut(optOut); em.merge(entity); tx.commit(); } catch (NotFoundException e) { throw e; } catch (Exception e) { if (tx.isActive()) { tx.rollback(); } logger.error("Could not updated event opted out status: {}", e.getMessage()); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public void updateEventOptOutStatus(Long eventId, boolean optOut) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; EntityTransaction tx = null; try { em = emf.createEntityManager(); tx = em.getTransaction(); tx.begin(); EventEntity entity = em.find(EventEntity.class, eventId); if (entity == null) { throw new NotFoundException("Event with ID " + eventId + " does not exist"); } entity.setOptOut(optOut); em.merge(entity); tx.commit(); } catch (NotFoundException e) { throw e; } catch (Exception e) { if (tx.isActive()) { tx.rollback(); } logger.error("Could not updated event opted out status: {}", e.getMessage()); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public ReviewStatus getReviewStatus(String mediapackageId) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); EventEntity event = getEventEntityByMpId(mediapackageId, em); if (event == null) throw new NotFoundException("Event with MP ID " + mediapackageId + " does not exist"); return event.getReviewStatus(); } catch (NotFoundException e) { throw e; } catch (Exception e) { logger.error("Could not retrieve review status for event with mediapackage '{}': {}", mediapackageId, e.getMessage()); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public Date getReviewDate(String mediapackageId) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); EventEntity event = getEventEntityByMpId(mediapackageId, em); if (event == null) throw new NotFoundException("Event with MP ID " + mediapackageId + " does not exist"); return event.getReviewDate(); } catch (NotFoundException e) { throw e; } catch (Exception e) { logger.error("Could not retrieve review date for event with mediapackage '{}': {}", mediapackageId, e.getMessage()); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public void updateEventReviewStatus(String mediapackageId, ReviewStatus reviewStatus, Date modificationDate) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; EntityTransaction tx = null; try { em = emf.createEntityManager(); tx = em.getTransaction(); tx.begin(); EventEntity entity = getEventEntityByMpId(mediapackageId, em); if (entity == null) throw new NotFoundException("Event with MP ID " + mediapackageId + " does not exist"); entity.setReviewStatus(reviewStatus); entity.setReviewDate(modificationDate); em.merge(entity); tx.commit(); } catch (NotFoundException e) { throw e; } catch (Exception e) { if (tx.isActive()) { tx.rollback(); } logger.error("Could not updated event review status: {}", e.getMessage()); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public boolean isBlacklisted(String mediapackageId) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); EventEntity event = getEventEntityByMpId(mediapackageId, em); if (event == null) throw new NotFoundException("Event with MP ID " + mediapackageId + " does not exist"); return event.isBlacklisted(); } catch (NotFoundException e) { throw e; } catch (Exception e) { logger.error("Could not retrieve blacklist status for event with mediapackage '{}': {}", mediapackageId, e.getMessage()); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public boolean isBlacklisted(Long eventId) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); EventEntity event = em.find(EventEntity.class, eventId); if (event == null) { throw new NotFoundException("Event with ID " + eventId + " does not exist"); } return event.isBlacklisted(); } catch (NotFoundException e) { throw e; } catch (Exception e) { logger.error("Could not retrieve review status for event with mediapackage '{}': {}", eventId, ExceptionUtils.getStackTrace(e)); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public void updateEventBlacklistStatus(String mediapackageId, boolean blacklisted) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; EntityTransaction tx = null; try { em = emf.createEntityManager(); tx = em.getTransaction(); tx.begin(); EventEntity entity = getEventEntityByMpId(mediapackageId, em); if (entity == null) throw new NotFoundException("Event with MP ID " + mediapackageId + " does not exist"); entity.setBlacklistStatus(blacklisted); em.merge(entity); tx.commit(); } catch (NotFoundException e) { throw e; } catch (Exception e) { if (tx.isActive()) { tx.rollback(); } logger.error("Could not updated event blacklist status: {}", e.getMessage()); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public void updateEventBlacklistStatus(Long eventId, boolean blacklisted) throws NotFoundException, SchedulerServiceDatabaseException { EntityManager em = null; EntityTransaction tx = null; try { em = emf.createEntityManager(); tx = em.getTransaction(); tx.begin(); EventEntity entity = em.find(EventEntity.class, eventId); if (entity == null) { throw new NotFoundException("Event with ID " + eventId + " does not exist"); } entity.setBlacklistStatus(blacklisted); em.merge(entity); tx.commit(); } catch (NotFoundException e) { throw e; } catch (Exception e) { if (tx.isActive()) { tx.rollback(); } logger.error("Could not updated event blacklist status: {}", e.getMessage()); throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public long countConfirmedResponses() throws SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); Query q = em.createNamedQuery("Event.countConfirmed"); Number countResult = (Number) q.getSingleResult(); return countResult.longValue(); } catch (Exception e) { throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public long countQuarterConfirmedResponses() throws SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); Query q = em.createNamedQuery("Event.countConfirmedByDateRange"); setDateForQuarterQuery(q); Number countResult = (Number) q.getSingleResult(); return countResult.longValue(); } catch (Exception e) { throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public long countDailyConfirmedResponses() throws SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); Query q = em.createNamedQuery("Event.countConfirmedByDateRange"); setDateForDailyQuery(q); Number countResult = (Number) q.getSingleResult(); return countResult.longValue(); } catch (Exception e) { throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public long countTotalResponses() throws SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); Query q = em.createNamedQuery("Event.countRespones"); Number countResult = (Number) q.getSingleResult(); return countResult.longValue(); } catch (Exception e) { throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public long countUnconfirmedResponses() throws SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); Query q = em.createNamedQuery("Event.countUnconfirmed"); Number countResult = (Number) q.getSingleResult(); return countResult.longValue(); } catch (Exception e) { throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } @Override public long countOptedOutResponses() throws SchedulerServiceDatabaseException { EntityManager em = null; try { em = emf.createEntityManager(); Query q = em.createNamedQuery("Event.countOptedOut"); Number countResult = (Number) q.getSingleResult(); return countResult.longValue(); } catch (Exception e) { throw new SchedulerServiceDatabaseException(e); } finally { if (em != null) em.close(); } } /** * Gets an event by its mediapackage ID. * * @param mediaPackageId * the mediapackage identifier * @param em * an open entity manager * @return the event entity, or null if not found */ protected EventEntity getEventEntityByMpId(String mediaPackageId, EntityManager em) { Query q = em.createNamedQuery("Event.findByMpId").setParameter("mpId", mediaPackageId); try { return (EventEntity) q.getSingleResult(); } catch (NoResultException e) { return null; } } /** The beginnings of a quarter independent from the year. */ private final List<Partial> quarterBeginnings = list(partial(DateTimeConstants.JANUARY, 1), partial(DateTimeConstants.APRIL, 1), partial(DateTimeConstants.JULY, 1), partial(DateTimeConstants.OCTOBER, 1)); private DateTimeFieldType[] partialFields; /** * Add the correct start and end value for the given daily count query. * <p> * Please note that the start instant is inclusive while the end instant is exclusive. * * @param query * The query where the parameters have to be added * @return the same query instance */ private Query setDateForDailyQuery(Query query) { final DateTime today = new DateTime().withTimeAtStartOfDay(); return query.setParameter("start", today.toDate()).setParameter("end", today.plusDays(1).toDate()); } /** * Add the correct start and end value for the given quarter count query * <p> * Please note that the start instant is inclusive while the end instant is exclusive. * * @param query * The query where the parameters have to be added * @return the same query instance */ private Query setDateForQuarterQuery(Query query) { final DateTime today = new DateTime().withTimeAtStartOfDay(); final Partial partialToday = partialize(today); final DateTime quarterBeginning = mlist(quarterBeginnings).foldl(quarterBeginnings.get(0), new Function2<Partial, Partial, Partial>() { @Override public Partial apply(Partial sum, Partial quarterBeginning) { return partialToday.isAfter(quarterBeginning) ? quarterBeginning : sum; } }).toDateTime(today); return query.setParameter("start", quarterBeginning.toDate()).setParameter("end", quarterBeginning.plusMonths(3).toDate()); } /** Create a Partial from an Instant extracting month and day. */ private Partial partialize(ReadableInstant instant) { return partial(instant.get(DateTimeFieldType.monthOfYear()), instant.get(DateTimeFieldType.dayOfMonth())); } private DateTimeFieldType[] getPartialFields() { if (partialFields == null) { partialFields = array(DateTimeFieldType.monthOfYear(), DateTimeFieldType.dayOfMonth()); } return partialFields; } /** Create a Partial consisting of only month and day. */ private Partial partial(int month, int dayOfMonth) { return new Partial(getPartialFields(), new int[] { month, dayOfMonth }); } }