Rename package and make-dist with maven offline mode
[aquarium] / src / main / scala / gr / grnet / aquarium / util / RandomEventGenerator.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.util
37
38 import akka.amqp._
39 import util.Random
40 import gr.grnet.aquarium.event.ResourceEvent
41 import scopt.OptionParser
42 import gr.grnet.aquarium.messaging.AkkaAMQP
43 import java.lang.StringBuffer
44 import gr.grnet.aquarium.logic.accounting.Policy
45 import gr.grnet.aquarium.store.memory.MemIMEvent
46 import gr.grnet.aquarium.event.im.{StdIMEvent, IMEventModel}
47
48 /**
49  *  Generates random resource events to use as input for testing and
50  *  injects them to the specified exchange.
51  *
52  * @author Georgios Gousios <gousiosg@gmail.com>
53  */
54 trait RandomEventGenerator extends AkkaAMQP {
55
56   val userIds = 1 to 1000
57   val clientIds = 1 to 4
58   val vmIds = 1 to 4000
59   val resources = Policy.policy.resources.map{r => r.name}
60   val tsFrom = 1293840000000L //1/1/2011 0:00:00 GMT
61   val tsTo = 1325376000000L   //1/1/2012 0:00:00 GMT
62   val eventVersion = 1 to 4
63
64   private val seed = 0xdeadbeef
65   private lazy val rnd = new Random(seed)
66
67   /**
68    * Generate a random resource event
69    */
70   def nextUserEvent(): IMEventModel = {
71     val ts = tsFrom + (scala.math.random * ((tsTo - tsFrom) + 1)).asInstanceOf[Long]
72
73     new StdIMEvent(
74       id = CryptoUtils.sha1(genRndAsciiString(35)),
75       occurredMillis = ts.toLong,
76       receivedMillis = ts.toLong,
77       userID = userIds(rnd.nextInt(100)).toString,
78       clientID = "defclient",
79       isActive = rnd.nextBoolean,
80       role = Array("PROF", "STUDENT", "ADMIN").apply(rnd.nextInt(3)),
81       eventVersion = 1.toString,
82       eventType = Array("ACTIVE", "SUSPENDED").apply(rnd.nextInt(2)),
83       details = Map()
84     )
85   }
86
87   /**
88    * Generate a random resource event
89    */
90   def genPublishUserEvents(num: Int) = {
91     val publisher = producer(im_exchanges(0))
92
93     (1 to num).foreach {
94       n =>
95         var event = nextUserEvent()
96         publisher ! Message(event.toJson.getBytes, "astakos.user")
97     }
98   }
99
100   /**
101    * Generete and publish create events for test users
102    */
103   def initUsers(num: Int) = {
104     val publisher = producer(im_exchanges(0))
105
106     userIds.filter(_ < num).foreach {
107       i =>
108         val ts = tsFrom + (scala.math.random * ((tsTo - tsFrom) + 1)).asInstanceOf[Long]
109         val user = new StdIMEvent(
110           id = CryptoUtils.sha1(genRndAsciiString(35)),
111           occurredMillis = ts.toLong,
112           receivedMillis = ts.toLong,
113           userID = i.toString,
114           clientID = "defclient",
115           isActive = rnd.nextBoolean,
116           role = Array("PROF", "STUDENT", "ADMIN").apply(rnd.nextInt(3)),
117           eventVersion = 1.toString,
118           eventType = "CREATE",
119           details = Map()
120         )
121         publisher ! Message(user.toJson.getBytes, "astakos.user")
122     }
123   }
124
125   /**
126    * Get the next random resource event
127    */
128   def nextResourceEvent() : ResourceEvent = {
129     val res = rnd.shuffle(resources).head
130
131     val extra = res match {
132       case "vmtime" => Map("vmid" -> rnd.nextInt(vmIds.max).toString)
133       case _ => Map[String, String]()
134     }
135
136     val value = res match {
137       case "vmtime" => rnd.nextInt(1)
138       case _ => rnd.nextInt(5000)
139     }
140
141     val ts = tsFrom + (scala.math.random * ((tsTo - tsFrom) + 1)).asInstanceOf[Long]
142     val str = genRndAsciiString(35)
143
144     ResourceEvent(
145       CryptoUtils.sha1(str),
146       ts, ts,
147       rnd.nextInt(userIds.max).toString,
148       rnd.nextInt(clientIds.max).toString,
149       res, "1", 1.toString, value, extra)
150   }
151
152   def genRndAsciiString(size: Int): String = {
153     (1 to size).map{
154       i => rnd.nextPrintableChar()
155     }.foldLeft(new StringBuffer()){
156       (a, b) => a.append(b)
157     }.toString
158   }
159
160   /**
161    * Generate resource events and publish them to the queue
162    */
163   def genPublishResEvents(num: Int) = {
164
165     assert(num > 0)
166     val publisher = producer(resevent_exchanges(0))
167
168     (1 to num).foreach {
169       n =>
170         var event = nextResourceEvent
171         publisher ! Message(event.toBytes,
172           "%s.%s.%s".format("",event.clientID, event.resource))
173     }
174   }
175 }
176
177 object RandomEventGen extends RandomEventGenerator {
178
179   case class Config(var i: Boolean = false,
180                     var u: Boolean = false,
181                     var r: Boolean = false,
182                     var nummsg: Int = 100)
183
184   val config = new Config
185
186   private val parser = new OptionParser("RandomEventGen") {
187     opt("i", "im-events", "Generate IM events", {config.i = true})
188     opt("u", "user-create", "Generate IM events that create users", {config.u = true})
189     opt("r", "resource-events", "Generate resource events", {config.r = true})
190     arg("nummsgs", "Number of msgs to generate", {num: String => config.nummsg = Integer.parseInt(num)})
191   }
192
193   def main(args: Array[String]): Unit = {
194
195     if (!parser.parse(args))
196       errexit
197
198     if (!config.i && !config.u && !config.r) {
199       println("One of -i, -u, -r must be specified")
200       errexit
201     }
202
203     println("Publishing %d msgs, hit Ctrl+c to stop".format(config.nummsg))
204     if (config.r) genPublishResEvents(config.nummsg)
205     if (config.u) initUsers(config.nummsg)
206     if (config.i) genPublishUserEvents(config.nummsg)
207   }
208   
209   private def errexit() = {
210     print(parser.usage)
211     System.exit(-1)
212   }
213 }