Rename conf to policy and make parentID optional (via null)
[aquarium] / src / main / scala / gr / grnet / aquarium / message / avro / FullPriceTableHelpers.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.message.avro
37
38 import gr.grnet.aquarium.message.avro.gen.{_EffectivePriceTable, _FullPriceTable}
39 import gr.grnet.aquarium.AquariumInternalError
40 import gr.grnet.aquarium.util.shortNameOfType
41 import gr.grnet.aquarium.util.LogHelpers.Debug
42 import org.slf4j.Logger
43 import scala.annotation.tailrec
44 import java.{util ⇒ ju}
45
46 /**
47  *
48  * @author Christos KK Loverdos <loverdos@gmail.com>
49  */
50 object FullPriceTableHelpers {
51   final val DefaultSelectorKey = "default"
52
53   def effectivePriceTableOfSelectorForResource(
54       fullPriceTable: _FullPriceTable,
55       selectorPath: List[CharSequence],
56       resource: String,
57       logger: Logger
58   ): _EffectivePriceTable = {
59
60       // Most of the code is for exceptional cases, which we identify in detail.
61       @tailrec
62       def find(
63           partialSelectorPath: List[CharSequence],
64           partialSelectorData: Any
65       ): _EffectivePriceTable = {
66
67         Debug(logger, "find: ")
68         Debug(logger, "  partialSelectorPath = %s", partialSelectorPath.mkString("/"))
69         Debug(logger, "  partialSelectorData = %s", partialSelectorData)
70
71         partialSelectorPath match {
72           case selector :: Nil ⇒
73             // One selector, meaning that the selectorData must be a Map[String, EffectivePriceTable]
74             partialSelectorData match {
75               case selectorMap: ju.Map[_,_] ⇒
76                 // The selectorData is a map indeed
77                 selectorMap.asInstanceOf[ju.Map[String, _]].get(selector) match {
78                   case null ⇒
79                     // The selectorData is a map but it does nto contain the selector
80                     throw new AquariumInternalError(
81                       "[AQU-SEL-002] Cannot select path %s for resource %s. Nothing found at partial selector path %s".format(
82                         selectorPath.mkString("/"),
83                         resource,
84                         partialSelectorPath.mkString("/")
85                       )
86                     )
87
88                   case selected: _EffectivePriceTable ⇒
89                     // Yes, it is a map of the right type (OK, we assume keys are always Strings)
90                     // (we only check the value type)
91                     selected
92
93                   case badSelected ⇒
94                     // The selectorData is a map but the value is not of the required type
95                     throw new AquariumInternalError(
96                       "[AQU-SEL-001] Cannot select path %s for resource %s. Found %s instead of an %s at partial selector path %s".format(
97                         selectorPath.mkString("/"),
98                         resource,
99                         badSelected,
100                         shortNameOfType[_EffectivePriceTable],
101                         partialSelectorPath.mkString("/")
102                       )
103                     )
104                 }
105
106
107               case badData ⇒
108                 // The selectorData is not a map. So we have just one final selector but no map to select from.
109                 throw new AquariumInternalError(
110                   "[AQU-SEL-003] Cannot select path %s for resource %s. Found %s instead of a Map at partial selector path %s".format(
111                     selectorPath.mkString("/"),
112                     resource,
113                     badData,
114                     partialSelectorPath.mkString("/")
115                   )
116                 )
117             }
118
119           case selector :: selectorTail ⇒
120             // More than one selector in the path, meaning that the selectorData must be a Map[String, Map[String, _]]
121             partialSelectorData match {
122               case selectorMap: ju.Map[_,_] ⇒
123                // The selectorData is a map indeed
124                 selectorMap.asInstanceOf[ju.Map[String,_]].get(selector) match {
125                   case null ⇒
126                     // The selectorData is a map but it does not contain the selector
127                     throw new AquariumInternalError(
128                       "[AQU-SEL-005] Cannot select path %s for resource %s. Nothing found at partial selector path %s".format(
129                         selectorPath.mkString("/"),
130                         resource,
131                         partialSelectorPath.mkString("/")
132                       )
133                     )
134
135                   case furtherSelectorMap: ju.Map[_,_] ⇒
136                     // The selectorData is a map and we found the respective value for the selector to be a map.
137                     find(selectorTail, furtherSelectorMap)
138
139                   case furtherBad ⇒
140                     // The selectorData is a map but the respective value is not a map, so that
141                     // the selectorTail path cannot be used.
142                     throw new AquariumInternalError(
143                       "[AQU-SEL-004] Cannot select path %s for resource %s. Found %s instead of a Map at partial selector path %s".format(
144                         selectorPath.mkString("/"),
145                         resource,
146                         furtherBad,
147                         partialSelectorPath.mkString("/")
148                        )
149                     )
150                 }
151
152               case badData ⇒
153                 // The selectorData is not a Map. So we have more than one selectors but no map to select from.
154                 throw new AquariumInternalError(
155                   "[AQU-SEL-006] Cannot select path %s for resource %s. Found %s instead of a Map at partial selector path %s".format(
156                     selectorPath.mkString("/"),
157                     resource,
158                     badData,
159                     partialSelectorPath.mkString("/")
160                   )
161                 )
162             }
163
164           case Nil ⇒
165             throw new AquariumInternalError(
166               "[AQU-SEL-007] No selector path for resource %s".format(resource)
167             )
168
169         }
170       }
171
172       Debug(logger, "effectivePriceTableOfSelectorForResource:")
173       Debug(logger, "  selectorPath = %s", selectorPath.mkString("/"))
174
175       val selectorData = fullPriceTable.getPerResource().get(resource)
176       if(selectorData eq null) {
177         throw new AquariumInternalError("Unknown resource type '%s'", resource)
178       }
179
180       Debug(logger, "  selectorData = %s", selectorData)
181       find(selectorPath, selectorData)
182   }
183
184 }