65bd024c6764bb9c4e4b6d74be64ec67fbba39e3
[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.logic.accounting.dsl.Timeslot
39 import gr.grnet.aquarium.message.avro.gen.PolicyMsg
40 import gr.grnet.aquarium.message.avro.{DummyHelpers, OrderingHelpers}
41 import gr.grnet.aquarium.store.PolicyStore
42 import gr.grnet.aquarium.util.Lock
43 import scala.collection.immutable
44
45 /**
46  * A caching [[gr.grnet.aquarium.store.PolicyStore]].
47  *
48  * @author Christos KK Loverdos <loverdos@gmail.com>
49  * @author Prodromos Gerakios <pgerakios@grnet.gr>
50  */
51
52 class CachingPolicyStore(defaultPolicy: PolicyMsg, policyStore: PolicyStore) extends PolicyStore {
53   private[this] final val lock = new Lock()
54
55   private[this] var _policies = immutable.TreeSet[PolicyMsg]()(OrderingHelpers.DefaultPolicyMsgOrdering)
56
57   def foreachPolicy[U](f: (PolicyMsg) ⇒ U) {
58     ensureLoaded {
59       _policies.foreach(f)
60     }
61   }
62
63   private[this] def ensureLoaded[A](andThen: ⇒ A): A = {
64     this.lock.withLock {
65       if(_policies.isEmpty) {
66         policyStore.foreachPolicy(_policies += _)
67
68         if(_policies.isEmpty) {
69           _policies += defaultPolicy
70          policyStore.insertPolicy(defaultPolicy)
71         }
72       }
73
74       andThen
75     }
76   }
77
78   def loadSortedPoliciesWithin(fromMillis: Long, toMillis: Long): immutable.SortedMap[Timeslot, PolicyMsg] = {
79     immutable.SortedMap(_policies.
80       from(DummyHelpers.dummyPolicyMsgAt(fromMillis)).
81       to(DummyHelpers.dummyPolicyMsgAt(toMillis)).toSeq.
82       map(p ⇒ (Timeslot(p.getValidFromMillis, p.getValidToMillis), p)): _*
83     )
84   }
85
86   /**
87    * Return the last (ordered) policy that starts before timeMillis
88    *
89    * @param atMillis
90    * @return
91    */
92   def loadPolicyAt(atMillis: Long): Option[PolicyMsg] =
93     ensureLoaded {
94     // Take the subset of all ordered policies up to the one with less than or equal start time
95     // and then return the last item. This should be the policy right before the given time.
96     // TODO: optimize the creation of the fake StdPolicy
97       _policies.to(DummyHelpers.dummyPolicyMsgAt(atMillis)).lastOption
98     }
99
100
101   /**
102    * Store an accounting policy.
103    */
104   def insertPolicy(policy: PolicyMsg): PolicyMsg = {
105     ensureLoaded {
106       this._policies += policy
107       policyStore.insertPolicy(policy)
108     }
109   }
110 }