Skip to content
This repository has been archived by the owner on Feb 8, 2019. It is now read-only.

Commit

Permalink
Merge pull request #15 from VinceMacBuche/ust_3231/dev_3416/Add_secti…
Browse files Browse the repository at this point in the history
…on_spec_serializer

Fixes #3416 : Add Section Spec serializer
  • Loading branch information
fanf committed Apr 11, 2013
2 parents cb7f8fe + 20e5bfc commit 28bbc38
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 9 deletions.
33 changes: 24 additions & 9 deletions src/main/scala/com/normation/cfclerk/domain/Constraint.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ import net.liftweb.common._

class ConstraintException(val msg: String) extends Exception(msg)


trait VTypeWithRegex {
def regex:Option[RegexConstraint]
}
/**
* A constraint about the type of a variable
*/
Expand All @@ -58,7 +62,7 @@ sealed trait VTypeConstraint {
else
x.replaceAll("""\\""", """\\\\""").replaceAll(""""""","""\\"""")
}

//check if the value is compatible with that type constrain.
//return a Failure on error, the checked value on success.
def getTypedValue(value:String, forField:String) : Box[Any] = Full(escapeString(value))
Expand All @@ -77,13 +81,24 @@ object VTypeConstraint {
PermVType :: PasswordVType(algos) :: UploadedFileVType :: DestinationPathVType ::
BooleanVType :: RawVType :: Nil ::: stringTypes(r)

def getRegexConstraint(vType : VTypeConstraint) : Option[RegexConstraint] =
vType match {
case withRegex:VTypeWithRegex => withRegex.regex
case _ => None
}

def getPasswordHash(vType : VTypeConstraint) : Seq[HashAlgoConstraint] = {
vType match {
case PasswordVType(hashes) => hashes
case _ => Seq()
}
}
def fromString(s:String, r: Option[RegexConstraint], algos:Seq[HashAlgoConstraint]) : Option[VTypeConstraint] = validTypes(r,algos).find(t => t.name == s)

val allTypeNames = validTypes(None,Seq()).map( _.name ).mkString(", ")
}

sealed trait StringVType extends VTypeConstraint {
sealed trait StringVType extends VTypeConstraint with VTypeWithRegex {
def regex: Option[RegexConstraint]

override def getTypedValue(value:String, forField:String) : Box[Any] = regex match {
Expand All @@ -104,7 +119,7 @@ object MailVType extends FixedRegexVType {
override val regex = Some(MailRegex)
}

case class IntegerVType(regex: Option[RegexConstraint] = None) extends VTypeConstraint {
case class IntegerVType(regex: Option[RegexConstraint] = None) extends VTypeConstraint with VTypeWithRegex {
override val name = "integer"
override def getTypedValue(value:String, forField:String) : Box[Any] = {
super.getTypedValue(value, forField).flatMap( _ =>
Expand All @@ -124,7 +139,7 @@ case class SizembVType(regex: Option[RegexConstraint] = None) extends SizeVType
case class SizegbVType(regex: Option[RegexConstraint] = None) extends SizeVType { override val name = "size-gb" }
case class SizetbVType(regex: Option[RegexConstraint] = None) extends SizeVType { override val name = "size-tb" }

case class DateTimeVType(regex: Option[RegexConstraint] = None) extends VTypeConstraint {
case class DateTimeVType(regex: Option[RegexConstraint] = None) extends VTypeConstraint with VTypeWithRegex {
override val name = "datetime"
override def getTypedValue(value:String, forField:String) : Box[Any] = {
super.getTypedValue(value, forField).flatMap( _ =>
Expand All @@ -136,8 +151,8 @@ case class DateTimeVType(regex: Option[RegexConstraint] = None) extends VTypeCon
)
}
}
case class DateVType(regex: Option[RegexConstraint] = None) extends VTypeConstraint { override val name = "date" }
case class TimeVType(regex: Option[RegexConstraint] = None) extends VTypeConstraint { override val name = "time" }
case class DateVType(regex: Option[RegexConstraint] = None) extends VTypeConstraint with VTypeWithRegex { override val name = "date" }
case class TimeVType(regex: Option[RegexConstraint] = None) extends VTypeConstraint with VTypeWithRegex { override val name = "time" }


//other types
Expand All @@ -162,9 +177,9 @@ case object BooleanVType extends VTypeConstraint {
case object UploadedFileVType extends VTypeConstraint { override val name = "uploadedfile" }
case object DestinationPathVType extends VTypeConstraint { override val name = "destinationfullpath" }
case object PermVType extends VTypeConstraint { override val name = "perm" }
case object RawVType extends VTypeConstraint {
override val name = "raw"
// no escaping for raw types
case object RawVType extends VTypeConstraint {
override val name = "raw"
// no escaping for raw types
override def getTypedValue(value:String, forField:String) : Box[Any] = Full(value)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package com.normation.cfclerk.xmlwriters

import net.liftweb.common._
import com.normation.cfclerk.domain._
import com.normation.cfclerk.xmlparsers.CfclerkXmlConstants._
import scala.xml._


trait SectionSpecWriter {

def serialize(rootSection:SectionSpec):Box[NodeSeq]

}

class SectionSpecWriterImpl extends SectionSpecWriter {


private[this] def createXmlTextNode(label : String, content : String) : Elem =
<tag>{Text(content)}</tag>.copy(label = label)

private[this] def createXmlNode(label : String, children : Seq[Node]) : Elem =
<tag>{children}</tag>.copy(label = label)

def serialize(rootSection:SectionSpec):Box[NodeSeq] = {
if (rootSection.name != SECTION_ROOT_NAME)
Failure(s"root section name should be equals to ${SECTION_ROOT_NAME} but is ${rootSection.name}")
else {
val children = (rootSection.children.flatMap( serializeChild(_))/:NodeSeq.Empty)((a,b) => a ++ b)
val xml = createXmlNode(SECTIONS_ROOT,children)
Full(xml)
}
}

private[this] def serializeChild(section:SectionChildSpec):NodeSeq = {
section match {
case s:SectionSpec => serializeSection(s)
case v:SectionVariableSpec => serializeVariable(v)
}
}

private[this] def serializeSection(section:SectionSpec):NodeSeq = {
val children = (section.children.flatMap( serializeChild(_))/:NodeSeq.Empty)((a,b) => a ++ b)
val xml = ( createXmlNode(SECTION,children)
% Attribute(SECTION_NAME, Text(section.name),Null)
% Attribute(SECTION_IS_MULTIVALUED, Text(section.isMultivalued.toString),Null)
% Attribute(SECTION_IS_COMPONENT, Text(section.isComponent.toString),Null)
)

// add ComponentKey attribute
section.componentKey.map{key =>
xml % Attribute(SECTION_COMPONENT_KEY,Text(key),Null)
}.getOrElse(xml)

}
private[this] def serializeVariable(variable:SectionVariableSpec):NodeSeq = {

val (label,valueLabels) = variable match {
case input:InputVariableSpec => (INPUT,Seq())
// Need to pattern match ValueLabel or compiler complains about missing patterns
case valueLabel:ValueLabelVariableSpec =>
val label = valueLabel match {
case select:SelectVariableSpec => SELECT
case selectOne:SelectOneVariableSpec => SELECT1
}

(label, valueLabel.valueslabels)
}

val name = createXmlTextNode(VAR_NAME, variable.name)
val description = createXmlTextNode(VAR_DESCRIPTION, variable.description)
val longDescription = createXmlTextNode(VAR_LONG_DESCRIPTION, variable.longDescription)
val isUnique = createXmlTextNode(VAR_IS_UNIQUE_VARIABLE, variable.isUniqueVariable.toString)
val isMultiValued = createXmlTextNode(VAR_IS_MULTIVALUED, variable.multivalued.toString)
val checked = createXmlTextNode(VAR_IS_CHECKED, variable.checked.toString)
val items = (valueLabels.map(serializeItem(_))/:NodeSeq.Empty)((a,b) => a ++ b)
val constraint = serializeConstraint(variable.constraint)

val children = ( name
++ description
++ longDescription
++ isUnique
++ isMultiValued
++ checked
++ items
++ constraint
).flatten

createXmlNode(label,children)
}

private[this] def serializeItem(item:ValueLabel):NodeSeq = {
val value = createXmlTextNode(CONSTRAINT_ITEM_VALUE,item.value)
val label = createXmlTextNode(CONSTRAINT_ITEM_LABEL,item.label)
val child = Seq(value,label)

createXmlNode(CONSTRAINT_ITEM,child)
}

private[this] def serializeConstraint(constraint:Constraint): NodeSeq = {
val constraintType = createXmlTextNode(CONSTRAINT_TYPE, constraint.typeName.name)
val empty = createXmlTextNode(CONSTRAINT_MAYBEEMPTY, constraint.mayBeEmpty.toString)
val regexp = VTypeConstraint.getRegexConstraint(constraint.typeName).map(regex =>
createXmlTextNode(CONSTRAINT_REGEX,regex.pattern)
) getOrElse(NodeSeq.Empty)
val dflt = constraint.default.map(createXmlTextNode(CONSTRAINT_DEFAULT,_)).getOrElse(NodeSeq.Empty)
val hashAlgos = createXmlTextNode(
CONSTRAINT_PASSWORD_HASH
, VTypeConstraint.getPasswordHash(constraint.typeName).map(_.prefix).mkString(",")
)

val children = Seq(constraintType,dflt,empty,regexp,hashAlgos).flatten

createXmlNode(VAR_CONSTRAINT,children)
}

}

0 comments on commit 28bbc38

Please sign in to comment.