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.aggregator; 19 20 import java.util.List; 21 22 import org.hibernate.Session; 23 import org.torweg.pulse.component.statistics.model.AbstractRegexVersioned; 24 import org.torweg.pulse.component.statistics.model.Visit; 25 import org.torweg.pulse.component.statistics.model.aggregation.AbstractRegexVersionedCounter; 26 import org.torweg.pulse.component.statistics.model.aggregation.AbstractRegexVersionedCounterAggregation; 27 import org.torweg.pulse.service.PulseException; 28 import org.torweg.pulse.util.time.Duration; 29 30 /** 31 * Passes the given {@code Visit} to {@code <T>} and stores the 32 * result of the aggregation to {@code <U>} on a per 33 * {@code Visit} basis. 34 * <p> 35 * Here <strong>on a per {@code Visit} basis</strong> means:<br/> 36 * A {@code Visit} extending over two days (e.g. first PIRecord [2009.01.01 37 * 23:59:59:999], second PIRecord [2009.01.02 00:00:00:000]) will only be 38 * aggregated once for - the first/start day of - the {@code Visit}. 39 * </p> 40 * 41 * @param <T> 42 * the {@code AbstractRegexVersioned} being processed by the 43 * {@code AbstractRegexVersionedPerVisitAggregator} 44 * @param <U> 45 * the matching 46 * {@code AbstractRegexVersionedCounterAggregation<?,?>} 47 * for {@code <T>} 48 * 49 * @author Daniel Dietz 50 * @version $Revision: 1541 $ 51 * 52 */ 53 public abstract class AbstractRegexVersionedPerVisitAggregator<T extends AbstractRegexVersioned, U extends AbstractRegexVersionedCounterAggregation<?, ?>> 54 extends AbstractBaseAggregator { 55 56 /** 57 * Aggregates information about the {@code AbstractVersioned}. 58 * 59 * @param visit 60 * the {@code Visit} to be processed 61 * @param s 62 * the current hibernate<sup>TM</sup>-{@code Session} 63 * 64 * @see org.torweg.pulse.component.statistics.aggregator.AbstractBaseAggregator 65 * #aggregate(org.torweg.pulse.component.statistics.model.Visit, 66 * org.hibernate.Session, 67 * org.torweg.pulse.component.statistics.DataAggregationJobletConfiguration) 68 */ 69 @Override 70 public final void aggregate(final Visit visit, final Session s) { 71 72 List<T> knownAbstractVersioneds = getKnownAbstractRegexVersioneds(s); 73 74 boolean foundMatch = false; 75 for (T abstractVersioned : knownAbstractVersioneds) { 76 if (abstractVersioned.isMatch(getCheckValue(visit))) { 77 countAndStore(abstractVersioned, visit, 78 visit.getFirstFullDay(), s); 79 foundMatch = true; 80 break; 81 } 82 } 83 if (!foundMatch) { 84 countAndStore(null, visit, visit.getFirstFullDay(), s); 85 } 86 } 87 88 /** 89 * Performs the actual aggregation. 90 * 91 * @param abstractVersioned 92 * the current {@code T} 93 * @param visit 94 * the current {@code Visit} 95 * @param fullDay 96 * a full day-{@code Duration} from the current visit 97 * @param s 98 * the current {@code Session} 99 * 100 * @throws PulseException 101 * if 102 * <ul> 103 * <li> 104 * <tt>abstractVersioned</tt> is {@code null} and the 105 * <strong>"unknown"</strong> could not be retrieved</li> 106 * <li>{@code <U>.aggregate(visit)} returns 107 * {@code false}</li> 108 * </ul> 109 */ 110 private void countAndStore(final T abstractVersioned, final Visit visit, 111 final Duration fullDay, final Session s) { 112 113 T checkedAbstractVersioned = abstractVersioned; 114 if (checkedAbstractVersioned == null) { 115 // load user-agent "unknown" 116 checkedAbstractVersioned = getUnknownAbstractRegexVersioned(s); 117 if (checkedAbstractVersioned == null) { 118 throw new PulseException("Failed loading \"unknown\"."); 119 } 120 } 121 122 // try load existing aggregation 123 U aggregation = getAbstractRegexVersionedCounterAggregation( 124 checkedAbstractVersioned, visit, fullDay, s); 125 126 if (aggregation == null) { 127 // create new aggregation 128 aggregation = getNewAbstractRegexVersionedCounterAggregation( 129 checkedAbstractVersioned, visit, fullDay); 130 s.saveOrUpdate(aggregation); 131 } 132 133 // aggregate 134 boolean success = aggregation.aggregate(visit, s); 135 if (!success) { 136 throw new PulseException(success + ": " + aggregation 137 + ".aggregate(" + visit + ")"); 138 } 139 140 // save 141 for (AbstractRegexVersionedCounter<?> counter : aggregation 142 .getVersionCounters()) { 143 s.saveOrUpdate(counter); 144 } 145 s.saveOrUpdate(aggregation); 146 147 } 148 149 /** 150 * Returns all the known {@code AbstractRegexVersioned}s of the type 151 * {@code <T>}. 152 * 153 * @param s 154 * the current Hibernate<sup>TM</sup>-{@code Session} 155 * 156 * @return {@code List<AbstractRegexVersioned>} of the type 157 * {@code <T>} 158 */ 159 protected abstract List<T> getKnownAbstractRegexVersioneds(final Session s); 160 161 /** 162 * Returns the string-value to be checked from the given {@code Visit}. 163 * 164 * @param visit 165 * the {@code Visit} 166 * 167 * @return the string-value to be checked 168 */ 169 protected abstract String getCheckValue(final Visit visit); 170 171 /** 172 * Returns the {@code AbstractRegexVersioned} of the type 173 * {@code <T>} which represents the "unknown". 174 * 175 * @param s 176 * the current Hibernate<sup>TM</sup>-{@code Session} 177 * 178 * @return the {@code AbstractRegexVersioned} of the type 179 * {@code <T>} which represents the "unknown" 180 */ 181 protected abstract T getUnknownAbstractRegexVersioned(final Session s); 182 183 /** 184 * Tries to load a matching 185 * {@code AbstractRegexVersionCounterAggregation<?,?>} for the 186 * given {@code AbstractRegexVersioned} of the type 187 * {@code <T>}, the given {@code Visit} and the given 188 * {@code Duration}. 189 * 190 * @param checkedAbstractRegexVersioned 191 * the {@code AbstractRegexVersioned} of the type 192 * {@code <T>} 193 * @param visit 194 * the {@code Visit} 195 * @param fullDay 196 * the {@code Duration} 197 * @param s 198 * the current Hibernate<sup>TM</sup>-{@code Session} 199 * 200 * @return a matching 201 * {@code AbstractRegexVersionCounterAggregation<?,?>} if 202 * available, {@code null} otherwise 203 */ 204 protected abstract U getAbstractRegexVersionedCounterAggregation( 205 final T checkedAbstractRegexVersioned, final Visit visit, 206 final Duration fullDay, final Session s); 207 208 /** 209 * Returns a new 210 * {@code AbstractRegexVersionCounterAggregation<?,?>} for the 211 * given {@code AbstractRegexVersioned} of the type 212 * {@code <T>}, the given {@code Visit} and the given 213 * {@code Duration}. 214 * 215 * @param checkedAbstractRegexVersioned 216 * the {@code AbstractRegexVersioned} of the type 217 * {@code <T>} 218 * @param visit 219 * the {@code Visit} 220 * @param fullDay 221 * the {@code Duration} 222 * 223 * @return a new 224 * {@code AbstractRegexVersionCounterAggregation<?,?>} 225 */ 226 protected abstract U getNewAbstractRegexVersionedCounterAggregation( 227 final T checkedAbstractRegexVersioned, final Visit visit, 228 final Duration fullDay); 229 230 } 231