Statistics
| Branch: | Tag: | Revision:

root / src / main / scala / com / normation / cfclerk / domain / VariableAndSectionSpec.scala @ 297687b8

History | View | Annotate | Download (11.7 kB)

1
/*
2
*************************************************************************************
3
* Copyright 2011 Normation SAS
4
*************************************************************************************
5
*
6
* This program is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU Affero General Public License as
8
* published by the Free Software Foundation, either version 3 of the
9
* License, or (at your option) any later version.
10
*
11
* In accordance with the terms of section 7 (7. Additional Terms.) of
12
* the GNU Affero GPL v3, the copyright holders add the following
13
* Additional permissions:
14
* Notwithstanding to the terms of section 5 (5. Conveying Modified Source
15
* Versions) and 6 (6. Conveying Non-Source Forms.) of the GNU Affero GPL v3
16
* licence, when you create a Related Module, this Related Module is
17
* not considered as a part of the work and may be distributed under the
18
* license agreement of your choice.
19
* A "Related Module" means a set of sources files including their
20
* documentation that, without modification of the Source Code, enables
21
* supplementary functions or services in addition to those offered by
22
* the Software.
23
*
24
* This program is distributed in the hope that it will be useful,
25
* but WITHOUT ANY WARRANTY; without even the implied warranty of
26
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27
* GNU Affero General Public License for more details.
28
*
29
* You should have received a copy of the GNU Affero General Public License
30
* along with this program. If not, see <http://www.gnu.org/licenses/agpl.html>.
31
*
32
*************************************************************************************
33
*/
34

    
35
package com.normation.cfclerk.domain
36

    
37
import com.normation.cfclerk.exceptions._
38
import scala.xml._
39
import net.liftweb.common._
40
import com.normation.cfclerk.xmlparsers.CfclerkXmlConstants._
41
import com.normation.utils.HashcodeCaching
42

    
43
/**
44
 * This file define the model for metadata of object 
45
 * contained in SECTIONS. 
46
 * A section may contains other section or variables. 
47
 */
48

    
49

    
50
/**
51
 * Generic trait for object in a section. 
52
 */
53
sealed trait SectionChildSpec {
54
  def name: String
55

    
56
  def getVariables: Seq[VariableSpec] = this match {
57
    case variable: SectionVariableSpec => Seq(variable)
58
    case section: SectionSpec => section.children.flatMap { child =>
59
      child match {
60
        case v: VariableSpec => Seq(v)
61
        case _ => Seq()
62
      }
63
    }
64
  }
65

    
66
  def getAllSections: Seq[SectionSpec] = this match {
67
    case v:SectionVariableSpec => Seq()
68
    case s:SectionSpec => s +: s.children.flatMap( _.getAllSections )
69
  }
70
  
71
  // get current variables and variables in sub section
72
  def getAllVariables: Seq[VariableSpec] = this match {
73
    case variable: SectionVariableSpec => Seq(variable)
74
    case section: SectionSpec =>
75
      section.children.flatMap(_.getAllVariables)
76
  }
77

    
78
  def filterByName(name: String): Seq[SectionChildSpec] = {
79
    val root = if (this.name == name) Seq(this) else Seq()
80

    
81
    val others = this match {
82
      case section: SectionSpec =>
83
        section.children.flatMap(_.filterByName(name))
84
      case variable: SectionVariableSpec => Seq()
85
    }
86
    root ++ others
87
  }
88
}
89

    
90

    
91
/**
92
 * Metadata about a section object. 
93
 */
94
case class SectionSpec(
95
    name: String
96
  , isMultivalued: Boolean = false
97
  , isComponent: Boolean = false
98
  , componentKey : Option[String] = None
99
  , foldable: Boolean = false
100
  , description: String = ""
101
  , children: Seq[SectionChildSpec] = Seq()
102
) extends SectionChildSpec with HashcodeCaching {
103

    
104
  lazy val getDirectVariables : Seq[VariableSpec] = {
105
    children.collect { case v:VariableSpec => v }
106
  }
107
  
108
  lazy val getDirectSections : Seq[SectionSpec] = {
109
    children.collect { case s:SectionSpec => s }
110
  }
111
  
112
  def copyWithoutSystemVars: SectionSpec =
113
    filterChildren {
114
      case variable: VariableSpec => !variable.isSystem
115
      case _ => true
116
    }
117

    
118
  // do recursively a filter on each SectionChild
119
  def filterChildren(f: SectionChildSpec => Boolean): SectionSpec = {
120
    val kept = children.filter(f) map { child =>
121
      child match {
122
        case secSpec: SectionSpec => secSpec.filterChildren(f)
123
        case varSpec: SectionVariableSpec => varSpec
124
      }
125
    }
126
    this.copy(children = kept)
127
  }
128

    
129
  def cloneVariablesInMultivalued: SectionSpec = {
130
    assert(isMultivalued)
131

    
132
    recCloneMultivalued
133
  }
134

    
135
  private def recCloneMultivalued: SectionSpec = {
136
    val multivaluedChildren = for (child <- children) yield child match {
137
      case s: SectionSpec =>
138
        if (s.isMultivalued) throw new TechniqueException(
139
          "A multivalued section should not contain other multivalued sections." +
140
            " It may contain only imbricated sections or variables.")
141
        else
142
          s.recCloneMultivalued
143
      case v: SectionVariableSpec => v.cloneSetMultivalued
144
    }
145

    
146
    copy(children = multivaluedChildren)
147
  }
148
}
149

    
150
object SectionSpec {
151
  def isSection(sectionName: String) = sectionName == "SECTION"
152
}
153

    
154
/**
155
 * Metadata about a Variable: name, description, type, etc
156
 * but no mutable data (no values)
157
 *
158
 */
159
sealed trait VariableSpec {
160
  type T <: VariableSpec
161
  type V <: Variable //type of variable linked to that variable spec
162

    
163
  def name: String
164
  def description: String
165
  def longDescription: String
166

    
167
  // a uniqueVariable has the same values over each policies
168
  def isUniqueVariable: Boolean
169
  def multivalued: Boolean
170

    
171
  // if true, check that the value set match the type  
172
  // Some value shouldn't be checked : when we set their value, we don't check anything
173
  def checked: Boolean
174

    
175
  //create a new variable from that spec
176
  def toVariable(values: Seq[String] = Seq()): V
177

    
178
  /*
179
   * children classes have to override that method
180
   * which make a clone of the spec, setting the
181
   * cloned to multivalued = true.
182
   * It's needed to handle multi instance in TemplateDependencies
183
   */
184
  def cloneSetMultivalued: T
185

    
186
  // it is a system variable only if the class extending this trait is 
187
  //  a SystemVariableSpec or a TrackerVariableSpec
188
  def isSystem: Boolean = {
189
    this match {
190
      case _: SystemVariableSpec | _: TrackerVariableSpec => true
191
      case _ => false
192
    }
193
  }
194

    
195
  def constraint: Constraint
196
}
197

    
198
case class SystemVariableSpec(
199
  override val name: String,
200
  val description: String,
201
  val longDescription: String = "",
202
  val valueslabels: Seq[ValueLabel] = Seq(),
203
  // a uniqueVariable has the same values over each policies
204
  val isUniqueVariable: Boolean = false,
205
  val multivalued: Boolean = false,
206

    
207
  // we expect that by default the variable will be checked
208
  val checked: Boolean = true,
209

    
210
  val constraint: Constraint = Constraint()
211
  
212
) extends VariableSpec with HashcodeCaching {
213

    
214
  override type T = SystemVariableSpec
215
  override type V = SystemVariable
216
  override def cloneSetMultivalued: SystemVariableSpec = this.copy(multivalued = true)
217
  def toVariable(values: Seq[String] = Seq()): SystemVariable = SystemVariable(this, values)
218
}
219

    
220

    
221
case class TrackerVariableSpec(
222
  val boundingVariable: Option[String] = None
223
) extends VariableSpec with HashcodeCaching {
224

    
225
  override type T = TrackerVariableSpec
226
  override type V = TrackerVariable
227

    
228
  override val name: String = TRACKINGKEY
229
  override val description: String = "Variable which kept information about the policy"
230

    
231
  override  val isUniqueVariable: Boolean = false
232

    
233
  override val checked: Boolean = false
234

    
235
  val constraint: Constraint = Constraint()
236
 
237
  override val multivalued = true
238
  override val longDescription = ""
239
  override def cloneSetMultivalued: TrackerVariableSpec = this.copy()
240
  def toVariable(values: Seq[String] = Seq()): TrackerVariable = TrackerVariable(this, values)
241
}
242

    
243
/**
244
 * Here we have all the variable that can be declared in sections
245
 * (all but system vars). 
246
 */
247
sealed trait SectionVariableSpec extends SectionChildSpec with VariableSpec {
248
  override type T <: SectionVariableSpec
249
}
250

    
251
case class ValueLabel(value: String, label: String) extends HashcodeCaching  {
252
  def tuple = (value, label)
253
  def reverse = ValueLabel(label, value)
254
}
255

    
256
trait ValueLabelVariableSpec extends SectionVariableSpec {
257
  val valueslabels: Seq[ValueLabel]
258
}
259

    
260
case class SelectVariableSpec(
261
  override val name: String,
262
  val description: String,
263
  val longDescription: String = "",
264
  val valueslabels: Seq[ValueLabel] = Seq(),
265
  // a uniqueVariable has the same values over each policies
266
  val isUniqueVariable: Boolean = false,
267
  val multivalued: Boolean = false,
268

    
269
  // we expect that by default the variable will be checked
270
  val checked: Boolean = true,
271

    
272
  val constraint: Constraint = Constraint()
273
  
274
) extends ValueLabelVariableSpec with HashcodeCaching {
275

    
276
  override type T = SelectVariableSpec
277
  override type V = SelectVariable
278
  override def cloneSetMultivalued: SelectVariableSpec = this.copy(multivalued = true)
279
  def toVariable(values: Seq[String] = Seq()): SelectVariable = SelectVariable(this, values)
280
}
281

    
282
case class SelectOneVariableSpec(
283
  override val name: String,
284
  val description: String,
285
  val longDescription: String = "",
286
  val valueslabels: Seq[ValueLabel] = Seq(),
287
  // a uniqueVariable has the same values over each policies
288
  val isUniqueVariable: Boolean = false,
289
  val multivalued: Boolean = false,
290

    
291
  // we expect that by default the variable will be checked
292
  val checked: Boolean = true,
293

    
294
  val constraint: Constraint = Constraint()
295

    
296
) extends ValueLabelVariableSpec with HashcodeCaching {
297

    
298
  override type T = SelectOneVariableSpec
299
  override type V = SelectOneVariable
300
  override def cloneSetMultivalued: SelectOneVariableSpec = this.copy(multivalued = true)
301
  def toVariable(values: Seq[String] = Seq()): SelectOneVariable = SelectOneVariable(this, values)
302
}
303

    
304
case class InputVariableSpec(
305
  override val name: String,
306
  val description: String,
307
  val longDescription: String = "",
308
  // a uniqueVariable has the same values over each policies
309
  val isUniqueVariable: Boolean = false,
310
  val multivalued: Boolean = false,
311

    
312
  // we expect that by default the variable will be checked
313
  val checked: Boolean = true,
314

    
315
  val constraint: Constraint = Constraint()
316

    
317
) extends SectionVariableSpec with HashcodeCaching {
318

    
319
  override type T = InputVariableSpec
320
  override type V = InputVariable
321
  override def cloneSetMultivalued: InputVariableSpec = this.copy(multivalued = true)
322
  def toVariable(values: Seq[String] = Seq()): InputVariable = InputVariable(this, values)
323
}
324

    
325

    
326
/**
327
 * This object is the central parser for VariableSpec, so
328
 * it has to know all possible VariableSpec type.
329
 * The pattern matching means that it won't be easily extended.
330
 * A more plugable architecture (partial function, pipeline...)
331
 * will have to be set-up to achieve such a goal.
332
 */
333
object SectionVariableSpec {  
334
  def markerNames = List(INPUT, SELECT1, SELECT)
335

    
336
  def isVariable(variableName: String) = markerNames contains variableName
337

    
338
  /**
339
   * Default variable implementation
340
   * Some of the arguments are not used by all implementations of Variable.
341
   * For instance, boundingVariable is only used for policyinstance variable.
342
   */
343
  def apply(
344
    varName: String,
345
    description: String,
346
    markerName: String,
347
    longDescription: String = "",
348
    valueslabels: Seq[ValueLabel],
349
    // a uniqueVariable has the same values over each policies
350
    isUniqueVariable: Boolean = false,
351
    multivalued: Boolean = false,
352
    checked: Boolean = true,
353
    constraint: Constraint = Constraint()): SectionVariableSpec = {
354

    
355
    markerName match {
356
      case INPUT => InputVariableSpec(varName, description, longDescription,
357
        isUniqueVariable, multivalued, checked, constraint)
358
      case SELECT => SelectVariableSpec(varName, description, longDescription,
359
        valueslabels, isUniqueVariable, multivalued, checked, constraint)
360
      case SELECT1 => SelectOneVariableSpec(varName, description, longDescription,
361
        valueslabels, isUniqueVariable, multivalued, checked, constraint)
362
      case x => throw new IllegalArgumentException("Unknown variable kind: " + x)
363
    }
364
  }
365
}
366