Statistics
| Branch: | Tag: | Revision:

root / utils / src / main / scala / com / normation / utils / Control.scala @ 80a3cdf0

History | View | Annotate | Download (3.4 kB)

1
/*
2
*************************************************************************************
3
* Copyright 2011 Normation SAS
4
*************************************************************************************
5
*
6
* Licensed under the Apache License, Version 2.0 (the "License");
7
* you may not use this file except in compliance with the License.
8
* You may obtain a copy of the License at
9
*
10
* http://www.apache.org/licenses/LICENSE-2.0
11
*
12
* Unless required by applicable law or agreed to in writing, software
13
* distributed under the License is distributed on an "AS IS" BASIS,
14
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
* See the License for the specific language governing permissions and
16
* limitations under the License.
17
*
18
*************************************************************************************
19
*/
20

    
21
package com.normation.utils
22

    
23
import net.liftweb.common._
24

    
25
/**
26
 * 
27
 * Interesting control structures
28
 *
29
 */
30
object Control {
31

    
32
  /**
33
   * Instance of the application function to Iterable and Box.
34
   * Transform a TraversableOnce[Box] into a Box[Iterable]
35
   * note: I don't how to say T<:TravesableOnce , T[Box[U]] => Box[T[U]]
36
   */ 
37
  implicit def boxSequence[U](seq:Seq[Box[U]]) : Box[Seq[U]] = {
38
    val buf = scala.collection.mutable.Buffer[U]()
39
    seq.foreach {
40
      case Full(u) => buf += u
41
      case e:EmptyBox => return e
42
    }
43
    Full(buf)
44
  }
45
 
46
  def sequence[U,T](seq:Seq[U])(f:U => Box[T]) : Box[Seq[T]] = {
47
    val buf = scala.collection.mutable.Buffer[T]()
48
    seq.foreach { u => f(u) match {
49
      case e:EmptyBox => return e 
50
      case Full(x) => buf += x
51
    } }
52
    Full(buf)
53
  }
54

    
55
  def sequenceEmptyable[U,T](seq:Seq[U])(f:U => Box[T]) : Box[Seq[T]] = {
56
    val buf = scala.collection.mutable.Buffer[T]()
57
    seq.foreach { u => f(u) match {
58
      case f:Failure => return f
59
      case Empty => // nothing to do
60
      case Full(x) => buf += x
61
    } }
62
    Full(buf)
63
  }
64

    
65
  
66
  /**
67
   * A version of sequence that will try to reach the end and accumulate
68
   * results
69
   * In case of error, it provides a failure with all accumulated 
70
   * other failure that leads to it
71
   */
72
  def bestEffort[U,T](seq:Seq[U])(f:U => Box[T]) : Box[Seq[T]] = {
73
    val buf = scala.collection.mutable.Buffer[T]()
74
    var errors = Option.empty[Failure]
75
    seq.foreach { u => f(u) match {
76
      case e:EmptyBox => 
77
        val msg = "Error processing %s".format(u)
78
        errors match {
79
          case None => errors = Some(e ?~! msg)
80
          case Some(f) => errors = Some(Failure(msg, Empty, Full(f)))
81
        }
82
      case Full(x) => buf += x
83
    } }
84
    errors.getOrElse(Full(buf))
85
  }  
86
  /**
87
   * A version of sequence that also provide the last output as input 
88
   * of the next processing (it's a foldleft)
89
   * 
90
   * Exemple of use:
91
   * init value : a report 
92
   * processors: a sequence of objects with an id, and a processReport method
93
   * 
94
   * for {
95
   *   processingOk <- pipeline(processors, initialReport) { case(processor, report) =>
96
   *     processor(report) ?~! "Error when processing report with processor '%s'".format(processor.id)
97
   *   }
98
   * } yield { processingOk } //match on Failure / Full(report)
99
   */
100
  def pipeline[T,U](seq: Seq[T],init:U)(call:(T,U) => Box[U]) : Box[U] = {
101
    ((Full(init):Box[U]) /: seq){ (currentValue, nextProcessor) => 
102
      currentValue match {
103
        case x:EmptyBox => return x //interrupt pipeline early
104
        case Full(value) => call(nextProcessor,value)
105
      }
106
    }
107
  }
108
}