4e1e8849e837a8e7b230a9816fd3fc7fc405bc19
[aquarium] / src / main / scala / gr / grnet / aquarium / policy / CachingPolicyStore.scala
1 /*
2  * Copyright 2011-2012 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *
12  *   2. Redistributions in binary form must reproduce the above
13  *      copyright notice, this list of conditions and the following
14  *      disclaimer in the documentation and/or other materials
15  *      provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * The views and conclusions contained in the software and
31  * documentation are those of the authors and should not be
32  * interpreted as representing official policies, either expressed
33  * or implied, of GRNET S.A.
34  */
35
36 package gr.grnet.aquarium.policy
37
38 import gr.grnet.aquarium.Timespan
39 import gr.grnet.aquarium.util.Lock
40 import gr.grnet.aquarium.store.PolicyStore
41 import gr.grnet.aquarium.logic.accounting.dsl.Timeslot
42 import collection.immutable
43
44 /**
45  * A caching [[gr.grnet.aquarium.store.PolicyStore]].
46  *
47  * @author Christos KK Loverdos <loverdos@gmail.com>
48  * @author Prodromos Gerakios <pgerakios@grnet.gr>
49  */
50
51 class CachingPolicyStore(defaultPolicy: PolicyModel, policyStore: PolicyStore) extends PolicyStore {
52   private[this] final val lock = new Lock()
53   private[this] final val EmptyPolicyByTimeslotMap = immutable.SortedMap[Timeslot, PolicyModel]()
54
55   private[this] var _policies = immutable.TreeSet[PolicyModel]()
56
57   private[this] def ensureLoaded[A](andThen: ⇒ A): A = {
58     this.lock.withLock {
59       if(_policies.isEmpty) {
60         _policies ++= policyStore.loadAllPolicies
61
62         if(_policies.isEmpty) {
63           _policies += defaultPolicy
64          policyStore.insertPolicy(defaultPolicy)
65         }
66       }
67
68       andThen
69     }
70   }
71
72   private[this] def policyAt(s:Long) : PolicyModel =
73     new StdPolicy("", None, Timespan(s), Set(), Set(), Map())
74
75   def loadAndSortPoliciesWithin(fromMillis: Long, toMillis: Long): immutable.SortedMap[Timeslot, PolicyModel] =
76     ensureLoaded {
77       val range = Timeslot(fromMillis,toMillis)
78       /* ``to'' method: return the subset of all policies.from <= range.to */
79       _policies.to(policyAt(range.to.getTime)).foldLeft (EmptyPolicyByTimeslotMap) { (map,p) =>
80         if(p.validityTimespan.toTimeslot.to.getTime >= range.from.getTime)
81           map + ((p.validityTimespan.toTimeslot,p))
82         else
83           map
84       }
85     }
86
87
88   /**
89    * Return the last (ordered) policy that starts before timeMillis
90    *
91    * @param atMillis
92    * @return
93    */
94   def loadValidPolicyAt(atMillis: Long): Option[PolicyModel] =
95     ensureLoaded {
96     // Take the subset of all ordered policies up to the one with less than or equal start time
97     // and then return the last item. This should be the policy right before the given time.
98     // TODO: optimize the creation of the fake StdPolicy
99       _policies.to(policyAt(atMillis)).lastOption
100     }
101
102
103   /**
104    * Store an accounting policy.
105    */
106   def insertPolicy(policy: PolicyModel): PolicyModel = {
107     ensureLoaded {
108       this._policies += policy
109       policyStore.insertPolicy(policy)
110     }
111   }
112 }