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.ManyToOne;
22   import javax.persistence.MappedSuperclass;
23   import javax.xml.bind.annotation.XmlAccessOrder;
24   import javax.xml.bind.annotation.XmlAccessType;
25   import javax.xml.bind.annotation.XmlAccessorOrder;
26   import javax.xml.bind.annotation.XmlAccessorType;
27   import javax.xml.bind.annotation.XmlAttribute;
28   import javax.xml.bind.annotation.XmlElement;
29   import javax.xml.bind.annotation.XmlRootElement;
30   import javax.xml.bind.annotation.XmlTransient;
31   
32   import org.hibernate.LazyInitializationException;
33   import org.hibernate.Session;
34   import org.slf4j.Logger;
35   import org.slf4j.LoggerFactory;
36   import org.torweg.pulse.component.statistics.model.StatisticsServer;
37   import org.torweg.pulse.component.statistics.model.Visit;
38   import org.torweg.pulse.util.entity.AbstractBasicEntity;
39   import org.torweg.pulse.util.time.Duration;
40   import org.torweg.pulse.util.time.IHasDuration;
41   import org.torweg.pulse.util.time.Period;
42   
43   /**
44    * Abstract bass class representing a basic aggregation of statistical data (by
45    * aggregating {@code Visit}s) as being produced by an {@code
46    * AbstractBaseAggregator}.
47    * 
48    * @author Daniel Dietz
49    * @version $Revision: 1579 $
50    * 
51    */
52   @XmlRootElement(name = "abstract-aggregation")
53   @XmlAccessorOrder(XmlAccessOrder.UNDEFINED)
54   @XmlAccessorType(XmlAccessType.FIELD)
55   @MappedSuperclass
56   public abstract class AbstractAggregation extends AbstractBasicEntity implements
57           IHasDuration {
58   
59       /**
60        * The serialVersionUID.
61        */
62       private static final long serialVersionUID = 8961277121778921282L;
63   
64       /**
65        * the logger.
66        */
67       protected static final Logger LOGGER = LoggerFactory
68               .getLogger(AbstractAggregation.class);
69   
70       /**
71        * The start time(-stamp) of the {@code AbstractAggregation}.
72        */
73       @Basic(optional = false)
74       @XmlAttribute(name = "start-time")
75       private long startTime;
76   
77       /**
78        * The end time(-stamp) of the {@code AbstractAggregation}.
79        */
80       @Basic(optional = false)
81       @XmlAttribute(name = "end-time")
82       private long endTime;
83   
84       /**
85        * The {@code StatisticsServer} this aggregation is related to.
86        */
87       @ManyToOne(optional = false)
88       @XmlTransient
89       // getter JAXB-annotated
90       private StatisticsServer statisticsServer;
91   
92       /**
93        * Sets the start time-stamp.
94        * 
95        * @param start
96        *            the start time to set
97        */
98       protected final void setStartMillis(final long start) {
99           this.startTime = start;
100      }
101  
102      /**
103       * Returns the start time-stamp.
104       * 
105       * @return the <tt>startTime</tt>
106       */
107      public final long getStartMillis() {
108          return this.startTime;
109      }
110  
111      /**
112       * Sets the end time-stamp.
113       * 
114       * @param end
115       *            the end time to set
116       */
117      protected final void setEndMillis(final long end) {
118          this.endTime = end;
119      }
120  
121      /**
122       * Returns the end time-stamp.
123       * 
124       * @return the <tt>endTime</tt>
125       */
126      public final long getEndMillis() {
127          return this.endTime;
128      }
129  
130      /**
131       * Sets the start/end of the {@code AbstractAggregation} from the given
132       * {@code Duration}.
133       * 
134       * @param duration
135       *            the {@code Duration} to apply
136       * 
137       * @throws NullPointerException
138       *             if the given {@code Duration} is {@code null}
139       * @throws IllegalArgumentException
140       *             if the given {@code Duration} does not match a valid {@code
141       *             Period}
142       */
143      protected final void setDuration(final Duration duration) {
144          if (duration == null) {
145              throw new NullPointerException("Given duration must not be null");
146          }
147          if (Period.valueof(duration).equals(Period.UNDEFINED)) {
148              throw new IllegalArgumentException(
149                      "Given duration must not be Period.UNDEFINED but match a valid "
150                              + "Period [SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR].");
151          }
152          setStartMillis(duration.getStartMillis());
153          setEndMillis(duration.getEndMillis());
154      }
155  
156      /**
157       * Returns a {@code Duration} representing the start/end of the {@code
158       * AbstractAggregation}.
159       * 
160       * @return a {@code Duration}
161       */
162      @XmlElement(name = "duration")
163      public final Duration getDuration() {
164          return new Duration(getStartMillis(), getEndMillis());
165      }
166  
167      /**
168       * Returns the data resolution as {@code Period}.
169       * 
170       * @return the data resolution as {@code Period}
171       */
172      @XmlElement(name = "data-resolution")
173      public final Period getDataResolution() {
174          return Period.valueof(getDuration());
175      }
176  
177      /**
178       * Returns the {@code StatisticsServer} the aggregation is related to.
179       * 
180       * @return the {@code StatisticsServer}
181       */
182      @XmlTransient
183      public final StatisticsServer getStatisticsServer() {
184          return this.statisticsServer;
185      }
186  
187      /**
188       * For JAXB only.
189       * 
190       * @return this.getStatisticsServer()
191       */
192      @XmlElement(name = "statistics-server")
193      @SuppressWarnings("unused")
194      @Deprecated
195      private StatisticsServer getStatisticsServerJAXB() { // NOPMD
196          try {
197              return getStatisticsServer();
198          } catch (LazyInitializationException e) {
199              LOGGER.debug("ignored: {}", e.getLocalizedMessage());
200              return null;
201          }
202      }
203  
204      /**
205       * Sets the {@code StatisticsServer}.
206       * 
207       * @param server
208       *            the {@code StatisticsServer}
209       * 
210       * @throws NullPointerException
211       *             if the given server is {@code null}
212       */
213      protected final void setStatisticsServer(final StatisticsServer server) {
214          if (server == null) {
215              throw new NullPointerException("Given server must not be null.");
216          }
217          this.statisticsServer = server;
218      }
219  
220      /**
221       * Checks if the given {@code Visit} can be aggregated by the {@code
222       * AbstractRegexVersionedCounterAggregation}.
223       * 
224       * @param visit
225       *            the {@code Visit}
226       * @return {@code true} if and only if the {@code Visit} can be processed,
227       *         {@code false} otherwise
228       */
229      public abstract boolean isAggregateable(final Visit visit);
230  
231      /**
232       * Aggregates the given {@code Visit}.
233       * 
234       * @param visit
235       *            the {@code Visit}
236       * @param s
237       *            a Hibernate<sup>TM</sup>-{@code Session}
238       * 
239       * @return {@code true} if and only if the {@code Visit} could be processed,
240       *         {@code false} otherwise
241       */
242      public abstract boolean aggregate(final Visit visit, final Session s);
243  
244      /**
245       * @return a string-representation of the {@code AbstractAggregation}
246       */
247      @Override
248      public String toString() {
249          return "{" + super.toString() + "@[" + getId() + "], duration: "
250                  + getDuration() + ", statisticsServer: "
251                  + getStatisticsServer() + "}";
252      }
253  
254      /**
255       * The known hours for the {@code PIRecordCountAggregation.HitCounter}.
256       * 
257       * @author Daniel Dietz
258       * @version $Revision: 1579 $
259       * 
260       */
261      public static enum Hour {
262          /**
263           * Zero [00:00:00:000 - 00:59:59:999].
264           */
265          ZERO(0),
266          /**
267           * One [01:00:00:000 - 01:59:59:999].
268           */
269          ONE(1),
270          /**
271           * Two [02:00:00:000 - 02:59:59:999].
272           */
273          TWO(2),
274          /**
275           * Three [03:00:00:000 - 03:59:59:999].
276           */
277          THREE(3),
278          /**
279           * Four [04:00:00:000 - 04:59:59:999].
280           */
281          FOUR(4),
282          /**
283           * Five [05:00:00:000 - 05:59:59:999].
284           */
285          FIVE(5),
286          /**
287           * Six [06:00:00:000 - 06:59:59:999].
288           */
289          SIX(6),
290          /**
291           * Seven [07:00:00:000 - 07:59:59:999].
292           */
293          SEVEN(7),
294          /**
295           * Eight [08:00:00:000 - 08:59:59:999].
296           */
297          EIGHT(8),
298          /**
299           * Nine [09:00:00:000 - 09:59:59:999].
300           */
301          NINE(9),
302          /**
303           * Ten [10:00:00:000 - 10:59:59:999].
304           */
305          TEN(10),
306          /**
307           * Eleven [11:00:00:000 - 11:59:59:999].
308           */
309          ELEVEN(11),
310          /**
311           * Twelve [12:00:00:000 - 12:59:59:999].
312           */
313          TWELVE(12),
314          /**
315           * Thirteen [13:00:00:000 - 13:59:59:999].
316           */
317          THIRTEEN(13),
318          /**
319           * Fourteen [14:00:00:000 - 14:59:59:999].
320           */
321          FOURTEEN(14),
322          /**
323           * Fifteen [15:00:00:000 - 15:59:59:999].
324           */
325          FIFTEEN(15),
326          /**
327           * Sixteen [16:00:00:000 - 16:59:59:999].
328           */
329          SIXTEEN(16),
330          /**
331           * Seventeen [17:00:00:000 - 17:59:59:999].
332           */
333          SEVENTEEN(17),
334          /**
335           * Eighteen [18:00:00:000 - 18:59:59:999].
336           */
337          EIGHTEEN(18),
338          /**
339           * Nineteen [19:00:00:000 - 19:59:59:999].
340           */
341          NINETEEN(19),
342          /**
343           * Twenty [20:00:00:000 - 20:59:59:999].
344           */
345          TWENTY(20),
346          /**
347           * Twenty-one [21:00:00:000 - 21:59:59:999].
348           */
349          TWENTY_ONE(21),
350          /**
351           * Twenty-two [22:00:00:000 - 22:59:59:999].
352           */
353          TWENTY_TWO(22),
354          /**
355           * Twenty-three [23:00:00:000 - 23:59:59:999].
356           */
357          TWENTY_THREE(23);
358  
359          /**
360           * The integer value of the constant.
361           */
362          private int value;
363  
364          /**
365           * Private constructor.
366           * 
367           * @param v
368           *            the value
369           */
370          private Hour(final int v) {
371              this.value = v;
372          }
373  
374          /**
375           * Returns the value.
376           * 
377           * @return the <tt>value</tt>
378           */
379          public int getValue() {
380              return this.value;
381          }
382  
383          /**
384           * Returns the matching {@code Hour} for the given integer i if (-1 < i
385           * < 24), {@code null} otherwise.
386           * 
387           * @param i
388           *            the integer value
389           * 
390           * @return the matching {@code Hour} for the given integer, or {@code
391           *         null} if no matching {@code Hour} was found
392           */
393          public static Hour valueOf(final int i) {
394              if (i < 0 || i > 23) {
395                  return null;
396              }
397              for (Hour h : values()) {
398                  if (h.getValue() == i) {
399                      return h;
400                  }
401              }
402              return null;
403          }
404  
405      }
406  
407  }
408