1 /* 2 * Copyright 2009 :torweg free software group 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 * 17 */ 18 package org.torweg.pulse.component.statistics.model.aggregation; 19 20 import javax.persistence.Basic; 21 import javax.persistence.Entity; 22 import javax.xml.bind.annotation.XmlAccessOrder; 23 import javax.xml.bind.annotation.XmlAccessType; 24 import javax.xml.bind.annotation.XmlAccessorOrder; 25 import javax.xml.bind.annotation.XmlAccessorType; 26 import javax.xml.bind.annotation.XmlElement; 27 import javax.xml.bind.annotation.XmlRootElement; 28 29 import org.hibernate.Session; 30 import org.torweg.pulse.component.statistics.model.StatisticsServer; 31 import org.torweg.pulse.component.statistics.model.Visit; 32 import org.torweg.pulse.util.time.Duration; 33 34 /** 35 * Aggregates {@code Visit}s and stores information about the average time spent 36 * on a "per {@code Visit}" basis for the set {@code Duration}. 37 * 38 * @author Daniel Dietz 39 * @version $Revision: 1579 $ 40 */ 41 @XmlRootElement(name = "average-time-per-visit-aggregation") 42 @XmlAccessorOrder(XmlAccessOrder.UNDEFINED) 43 @XmlAccessorType(XmlAccessType.FIELD) 44 @Entity 45 public class AverageTimePerVisitAggregation extends AbstractAggregation 46 implements ICount { 47 48 /** 49 * The serialVersionUID. 50 */ 51 private static final long serialVersionUID = -8593340599059224392L; 52 53 /** 54 * The {@code Visit}-counter. 55 */ 56 @XmlElement(name = "counter") 57 @Basic 58 private int counter = 0; 59 60 /** 61 * The average time per {@code Visit} in milliseconds. 62 */ 63 @XmlElement(name = "time") 64 @Basic 65 private double time = 0; 66 67 /** 68 * Default constructor for Hibernate<sup>TM</sup> and JAXB. 69 */ 70 @Deprecated 71 protected AverageTimePerVisitAggregation() { 72 super(); 73 } 74 75 /** 76 * Creates a new {@code AverageTimePerVisitAggregation} with the given 77 * {@code StatisticsServer} and the given {@code Duration}. 78 * 79 * @param server 80 * the {@code StatisticsServer} 81 * @param duration 82 * the {@code Duration} 83 */ 84 public AverageTimePerVisitAggregation(final StatisticsServer server, 85 final Duration duration) { 86 super(); 87 setStatisticsServer(server); 88 setDuration(duration); 89 } 90 91 /** 92 * Returns the average time in milliseconds per {@code Visit}. 93 * 94 * @return the <tt>time</tt> 95 */ 96 public final double getTime() { 97 return this.time; 98 } 99 100 /** 101 * Returns the {@code Visit}-count. 102 * 103 * @return the counter 104 */ 105 public final int getCount() { 106 return this.counter; 107 } 108 109 /** 110 * Adds 1 to the internal counter counter. 111 */ 112 protected final void increase() { 113 this.counter++; 114 } 115 116 /** 117 * Adds the given integer to the internal counter. 118 * 119 * @param i 120 * an integer 121 * 122 * @throws IllegalArgumentException 123 * if the given i is less than zero 124 */ 125 protected final void increaseBy(final int i) { 126 if (i < 0) { 127 throw new IllegalArgumentException("Given i must not be < 0."); 128 } 129 this.counter += i; 130 } 131 132 /** 133 * Test if the given {@code Visit} is aggregate-able by this {@code 134 * CountryPerVisitAggregation}. 135 * 136 * @param visit 137 * the {@code Visit} 138 * 139 * @return {@code true} if and only if this {@code AbstractAggregation} can 140 * process the given {@code Visit}, {@code false} otherwise 141 * 142 * @see org.torweg.pulse.component.statistics.model.aggregation.AbstractAggregation 143 * #isAggregateable(org.torweg.pulse.component.statistics.model.Visit) 144 */ 145 @Override 146 public final boolean isAggregateable(final Visit visit) { 147 if (visit == null 148 || !getStatisticsServer().equals( 149 visit.getLastRecord().getStatisticsServer())) { 150 return false; 151 } 152 return true; 153 } 154 155 /** 156 * Aggregates the given {@code Visit}. 157 * 158 * @param visit 159 * the {@code Visit} 160 * @param s 161 * the {@code Session} UNUSED 162 * 163 * @return {@code true} if and only if the {@code Visit} has been processed, 164 * {@code false} otherwise 165 * 166 * @see org.torweg.pulse.component.statistics.model.aggregation.AbstractAggregation 167 * #aggregate(org.torweg.pulse.component.statistics.model.Visit) 168 */ 169 @Override 170 public final boolean aggregate(final Visit visit, final Session s) { 171 172 if (!isAggregateable(visit)) { 173 LOGGER.warn("{} CANNOT AGGREGATE{}", this, visit); 174 return false; 175 } 176 177 // calculate average time per visit 178 this.time = ((this.counter * this.time) + visit.getTimeSpan(true) 179 .getMilliseconds()) 180 / (this.counter + 1); 181 182 // increase internal visit-counter 183 increase(); 184 185 return true; 186 } 187 188 /** 189 * Adds the values of the given {@code AverageTimePerVisitAggregation} if 190 * its {@code Duration} lies within the {@code Duration} of the current 191 * {@code AverageTimePerVisitAggregation}. 192 * 193 * @param aggr 194 * the {@code AverageTimePerVisitAggregation} 195 * @throws NullPointerException 196 * if the given {@code AverageTimePerVisitAggregation} is 197 * {@code null} 198 * @throws IllegalArgumentException 199 * if the {@code Duration} of the given {@code 200 * AverageTimePerVisitAggregation} does not lie within the 201 * {@code Duration} of the current {@code 202 * AverageTimePerVisitAggregation} 203 */ 204 public final void accumulate(final AverageTimePerVisitAggregation aggr) { 205 if (aggr == null) { 206 throw new NullPointerException( 207 "The given AverageTimePerVisitAggregation aggr must not be null."); 208 } 209 if (!getDuration().contains(aggr.getDuration())) { 210 throw new IllegalArgumentException( 211 "The duration [" 212 + aggr.getDuration() 213 + "] of the given AverageTimePerVisitAggregation does not lie within [" 214 + getDuration() + "]."); 215 } 216 // re-calculate average time per visit 217 this.time = ((this.counter * this.time) + (aggr.getTime() * aggr 218 .getCount())) 219 / (this.counter + aggr.getCount()); 220 increaseBy(aggr.getCount()); 221 } 222 223 } 224