/** * 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; import javax.persistence.Access; import javax.persistence.AccessType; import javax.persistence.Column; import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.MappedSuperclass; import javax.persistence.Transient; import org.apache.commons.lang.Validate; import org.apereo.portal.events.aggr.dao.jpa.DateDimensionImpl; import org.apereo.portal.events.aggr.dao.jpa.TimeDimensionImpl; import org.apereo.portal.events.aggr.groups.AggregatedGroupMapping; import org.apereo.portal.events.aggr.groups.AggregatedGroupMappingImpl; import org.hibernate.annotations.NaturalId; import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Base implementations for aggregations that are grouped by date, time, interval and group * */ @Access(AccessType.FIELD) @MappedSuperclass public abstract class BaseAggregationImpl< K extends BaseAggregationKey, D extends BaseGroupedAggregationDiscriminator> implements BaseAggregation<K, D> { private static final long serialVersionUID = 1L; @Transient private Logger logger = null; @NaturalId @ManyToOne(targetEntity = TimeDimensionImpl.class) @JoinColumn(name = "TIME_DIMENSION_ID", nullable = false) private final TimeDimension timeDimension; @NaturalId @ManyToOne(targetEntity = DateDimensionImpl.class) @JoinColumn(name = "DATE_DIMENSION_ID", nullable = false) private final DateDimension dateDimension; @NaturalId @Enumerated(EnumType.STRING) @Column(name = "AGGR_INTERVAL", nullable = false) private final AggregationInterval interval; @NaturalId @ManyToOne(targetEntity = AggregatedGroupMappingImpl.class) @JoinColumn(name = "AGGR_GROUP_ID", nullable = false) private final AggregatedGroupMapping aggregatedGroup; @Column(name = "DURATION", nullable = false) private int duration; @Transient private Boolean complete = null; @Transient private DateTime dateTime = null; protected BaseAggregationImpl() { this.timeDimension = null; this.dateDimension = null; this.interval = null; this.aggregatedGroup = null; } protected BaseAggregationImpl( TimeDimension timeDimension, DateDimension dateDimension, AggregationInterval interval, AggregatedGroupMapping aggregatedGroup) { Validate.notNull(timeDimension); Validate.notNull(dateDimension); Validate.notNull(interval); Validate.notNull(aggregatedGroup); this.timeDimension = timeDimension; this.dateDimension = dateDimension; this.interval = interval; this.aggregatedGroup = aggregatedGroup; } public abstract long getId(); @Override public DateTime getDateTime() { DateTime dt = this.dateTime; if (dt == null) { dt = this.timeDimension.getTime().toDateTime(this.dateDimension.getDate()); this.dateTime = dt; } return dt; } @Override public final TimeDimension getTimeDimension() { return this.timeDimension; } @Override public final DateDimension getDateDimension() { return this.dateDimension; } @Override public final AggregationInterval getInterval() { return this.interval; } @Override public final int getDuration() { return this.duration; } @Override public final AggregatedGroupMapping getAggregatedGroup() { return this.aggregatedGroup; } /** Set the duration of the interval */ public final void setDuration(int duration) { if (isComplete()) { this.getLogger() .warn( "{} is already closed, the new duration of {} will be ignored on: {}", this.getClass().getSimpleName(), duration, this); return; } this.duration = duration; } /** Mark the interval as complete, set the final duration the interval spans */ public final void intervalComplete(int duration) { this.duration = duration; this.completeInterval(); this.complete = Boolean.TRUE; } /** * Called to check if the interval is "complete". Defined as all data for the interval has been * handled and the final aggregation step(s) have been done. Implies that {@link * #completeInterval()} has been called at some point in the past */ protected abstract boolean isComplete(); /** * Called to tell the the aggregation that the interval it exists for has been completed and any * final calculations should be done */ protected abstract void completeInterval(); /** * @return The {@link Logger} to use for this event, lazy init as Loggers are rarely used for * events */ protected final Logger getLogger() { Logger l = this.logger; if (l == null) { l = LoggerFactory.getLogger(this.getClass()); this.logger = l; } return l; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((dateDimension == null) ? 0 : dateDimension.hashCode()); result = prime * result + ((aggregatedGroup == null) ? 0 : aggregatedGroup.hashCode()); result = prime * result + ((interval == null) ? 0 : interval.hashCode()); result = prime * result + ((timeDimension == null) ? 0 : timeDimension.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof BaseAggregationImpl)) return false; BaseAggregation<?, ?> other = (BaseAggregation<?, ?>) obj; if (dateDimension == null) { if (other.getDateDimension() != null) return false; } else if (!dateDimension.equals(other.getDateDimension())) return false; if (aggregatedGroup == null) { if (other.getAggregatedGroup() != null) return false; } else if (!aggregatedGroup.equals(other.getAggregatedGroup())) return false; if (interval != other.getInterval()) return false; if (timeDimension == null) { if (other.getTimeDimension() != null) return false; } else if (!timeDimension.equals(other.getTimeDimension())) return false; return true; } }