Wrapper for stored DSLPolicy YAML dumps
[aquarium] / src / main / scala / gr / grnet / aquarium / logic / accounting / Policy.scala
1 /*
2  * Copyright 2011 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.logic.accounting
37
38 import dsl.{Timeslot, DSLPolicy, DSL}
39 import gr.grnet.aquarium.Configurator._
40 import gr.grnet.aquarium.util.Loggable
41 import java.io.{InputStream, FileInputStream, File}
42 import java.util.Date
43 import com.ckkloverdos.maybe.{Maybe, Just}
44
45 /**
46  * Searches for and loads the applicable accounting policy
47  *
48  * @author Georgios Gousios <gousiosg@gmail.com>
49  */
50 object Policy extends DSL with Loggable {
51   
52   private var policies = {reloadPolicies}
53   
54   lazy val policy = loadPolicyFromFile(policyFile)
55
56   def policy(at: Date): Maybe[DSLPolicy] = Maybe {
57     policies.find {
58       a => a._1.from.before(at) &&
59            a._1.to.after(at)
60     } match {
61       case Some(x) => x._2
62       case None =>
63         throw new AccountingException("No valid policy for date: %s".format(at))
64     }
65   }
66
67   def policies(from: Date, to: Date): List[DSLPolicy] = {
68     policies.filter {
69       a => a._1.from.before(from) &&
70            a._1.to.after(to)
71     }.values.toList
72   }
73   
74   def policies(t: Timeslot): List[DSLPolicy] = policies(t.from, t.to)
75
76   def loadPolicyFromFile(pol: File): DSLPolicy = {
77
78     val stream = pol.exists() match {
79       case true =>
80         logger.info("Using policy file %s".format(pol.getAbsolutePath))
81         new FileInputStream(pol)
82       case false =>
83         logger.warn(("Cannot find user configured policy file %s, " +
84           "looking for default policy").format(pol.getAbsolutePath))
85         getClass.getClassLoader.getResourceAsStream("policy.yaml") match {
86           case x: InputStream =>
87             logger.warn("Using default policy, this is problably not what you want")
88             x
89           case null =>
90             logger.error("No valid policy file found, Aquarium will fail")
91             null
92         }
93     }
94     parse(stream)
95   }
96
97   private def policyFile: File =
98     MasterConfigurator.props.get(Keys.aquarium_policy) match {
99       case Just(x) => new File(x)
100       case _ => new File("/etc/aquarium/policy.yaml")
101     }
102
103   private def reloadPolicies(): Map[Timeslot, DSLPolicy] = synchronized {
104     //1. Load policies from db
105     val policies = MasterConfigurator.policyEventStore.loadPolicies(0)
106
107     //2. Check whether policy file has been updated
108     val latestPolicyChange = policies.last.validFrom
109     val policyf = policyFile
110     var updated = false
111
112     if (policyf.exists) {
113       if (policyf.lastModified > latestPolicyChange) {
114         updated = true
115       } else {
116         logger.info("Policy not changed since last check")
117       }
118     } else {
119       logger.warn("User specified policy file %s does not exist, " +
120         "using stored policy information".format(policyf.getAbsolutePath))
121     }
122
123     if (updated) {
124       //read from db etc
125     }
126
127     policies.foldLeft(Map[Timeslot, DSLPolicy]())(
128       (acc, p) =>
129         acc ++ Map(Timeslot(new Date(p.validFrom), new Date(p.validTo)) -> parse(p.policyYAML)))
130   }
131 }