2 * Copyright 2011-2012 GRNET S.A. All rights reserved.
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the following
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
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.
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.
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.
36 package gr.grnet.aquarium.logic.accounting.dsl
38 import java.util.{Date}
39 import scala.collection.immutable
40 import gr.grnet.aquarium.policy.{EffectiveUnitPrice, AdHocFullPriceTableRef, PolicyDefinedFullPriceTableRef, PolicyModel, ResourceType, EffectivePriceTable, UserAgreementModel}
41 import gr.grnet.aquarium.AquariumInternalError
44 * Utility functions to use when working with DSL types.
46 * @author Georgios Gousios <gousiosg@gmail.com>
51 * Resolves the effective price list for each chunk of the
52 * provided timeslot and returns it as a Map
54 def resolveEffectiveUnitPricesForTimeslot(
57 agreement: UserAgreementModel,
58 resourceType: ResourceType
59 ): immutable.SortedMap[Timeslot, Double] = {
61 val role = agreement.role
62 val fullPriceTable = agreement.fullPriceTableRef match {
63 case PolicyDefinedFullPriceTableRef ⇒
64 policy.roleMapping.get(role) match {
65 case Some(fullPriceTable) ⇒
69 throw new AquariumInternalError("Unknown role %s".format(role))
72 case AdHocFullPriceTableRef(fullPriceTable) ⇒
76 val effectivePriceTable = fullPriceTable.perResource.get(resourceType.name) match {
78 throw new AquariumInternalError("Unknown resource type %s".format(role))
80 case Some(effectivePriceTable) ⇒
84 resolveEffective3(timeslot, effectivePriceTable)
88 def resolveEffective3(
90 effectivePriceTable: EffectivePriceTable
91 ): immutable.SortedMap[Timeslot, Double/*unit price*/] = {
92 // assert(policy.toTimeslot contains timeslot0,"Policy does not contain timeslot")
93 val timeslot = timeslot0 //TODO: timeslot0.align(5000)
94 val subtimeslots_of_this_policy = Timeslot.mergeOverlaps(policy.effective intervalsOf timeslot)
95 val subtimeslots_NOT_IN_this_policy = Timeslot.mergeOverlaps(timeslot.nonOverlappingTimeslots
96 (subtimeslots_of_this_policy))
97 val policy_map = subtimeslots_of_this_policy.foldLeft (immutable.SortedMap[Timeslot, T]())
99 //Console.err.println("Adding timeslot" + t + " for policy " + policy.name)
102 val other_policy_map = policy.overrides match {
104 immutable.SortedMap[Timeslot, T]()
105 case Some(parent_policy)=>
106 subtimeslots_NOT_IN_this_policy.foldLeft (
107 (immutable.SortedMap[Timeslot, T]()))
109 //Console.err.println("Residual timeslot: " + t)
110 map ++ resolveEffective3(t,parent_policy)
113 val final_map = policy_map ++ other_policy_map
117 /*def resolveEffective2[T <: DSLTimeBoundedItem[T]](timeslot0: Timeslot,policy: T):
118 immutable.SortedMap[Timeslot, T] = {
119 assert(policy.toTimeslot contains timeslot0,"Policy does not contain timeslot")
121 /* generate mappings from timeslots -> policies
122 * Algorithm: find next valid date (starting from timeslot.start) in this policy
124 val timeslot = timeslot0 //TODO: timeslot0.align(5000)
125 def nextDate(d:Date,p:T) : Option[(Date,T,Boolean)] =
126 (p.effective nextValidAfter d,p.overrides) match {
127 case (None,None) => None
128 case (None,Some(parent_policy)) =>
129 val d1 = nextDate(d,parent_policy)
131 case (Some(d1),_) => /* the next valid date cannot occur after the end of timeslot*/
132 if (d1.before(timeslot.to)) Some((d1,p,true)) else Some((timeslot.to,p,false))
134 def genMap(map: immutable.SortedMap[Timeslot, T],d:Date) : immutable.SortedMap[Timeslot, T] = {
136 nextDate(d,policy) match {
138 case Some((d1,policy,cont)) =>
139 val t = Timeslot(d,d1)
140 val map1 = map + (t -> policy)
141 if(cont) genMap(map1,new Date(d1.getTime + step)) // 1 second after d1
145 val map = genMap(immutable.SortedMap[Timeslot, T](),timeslot.from)
150 * Splits the provided timeslot into chunks according to the validity
151 * timeslots specified by the provided time bounded item. It
152 * returns a map whose keys are the timeslot chunks and the values
153 * correspond to the effective time bounded item (algorithm or pricelist).
155 def resolveEffective1[T <: DSLTimeBoundedItem[T]](timeslot: Timeslot,policy: T):
156 immutable.SortedMap[Timeslot, T] = {
157 assert(policy.toTimeslot contains timeslot,"Policy does not contain timeslot")
159 /* Get a list of all effective/expanded policy timeslots within
160 a timeslot specified by "variable timeslot".
161 * NOTICE: The returned timeslots may be slightly out of "timeslot" bounds
162 * so we need to invoke overlappingTimeslots and nonOverlapping timeslots
164 val all_timeslots = allEffectiveTimeslots(policy.effective,timeslot)
165 val timeslots_IN_policy = timeslot.overlappingTimeslots(all_timeslots)
166 val timeslots_NOT_IN_policy = timeslot.nonOverlappingTimeslots(all_timeslots)
168 val ret = immutable.SortedMap[Timeslot, T]() ++
169 /*add [timeslots -> policy] covered by this policy*/
170 timeslots_IN_policy.flatMap {
171 effective_timeslot => Map(effective_timeslot -> policy)
173 /*add [timeslots -> policy] covered by parent policies */
174 timeslots_NOT_IN_policy.flatMap { /* search the policy hierarchy for effective timeslots not covered by this policy.*/
175 not_effective_timeslot => policy.overrides match {
176 case None => immutable.SortedMap[Timeslot, T]() /*Nothing to do. TODO: throw exception ?*/
177 case Some(parent_policy) => resolveEffective1(not_effective_timeslot,parent_policy) /* search the policy hierarchy*/
185 * Get a list of all timeslots within which a timeframe
186 * is effective, whithin the provided time bounds.
188 def allEffectiveTimeslots(spec: DSLTimeFrame, t: Timeslot):
190 if (spec.repeat.isEmpty) { //A simple timeframe with no repetition defined
191 val fromDate = if (spec.from.before(t.from)) t.from else spec.from
192 val toDate = if (spec.to.getOrElse(t.to).after(t.to)) t.to else spec.to.getOrElse(t.to)
193 List(Timeslot(fromDate, toDate))
194 } /* otherwise for all repetitions determine timeslots*/
196 val all = for { r <- spec.repeat
197 ts <- effectiveTimeslots(r, t.from, t.to)
199 //for{ i <- all} Console.err.println(i)
207 * Merges overlapping timeslots.
211 * Get a list of all timeslots within which a time frame is active.
212 The result is returned sorted by timeframe start date.
214 def effectiveTimeslots(spec: DSLTimeFrameRepeat, from: Date, to : Date):
216 for { (h1,h2) <- spec.start zip spec.end
217 (d1,d2) <- DSLTimeSpec.expandTimeSpec(h1,h2,from,to)
219 yield Timeslot(d1,d2)