88b48311a38386f17398acc71fe6a39e342b9bd8
[aquarium] / src / main / scala / gr / grnet / aquarium / store / LocalFSEventStore.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.store
37
38 import gr.grnet.aquarium.Configurator
39 import java.io.{FileOutputStream, File}
40 import gr.grnet.aquarium.logic.events.{UserEvent, ResourceEvent}
41 import gr.grnet.aquarium.util.{Loggable, makeBytes}
42 import com.ckkloverdos.maybe.{Just, Failed, Maybe}
43 import gr.grnet.aquarium.util.date.{TimeHelpers, MutableDateCalc}
44 import gr.grnet.aquarium.simulation.uid.{EAIOUUIDGenerator, UIDGenerator}
45
46 /**
47  * This is used whenever the property `events.store.folder` is setup in aquarium configuration.
48  *
49  * The public methods guarantee they will not propagate any failure.
50  *
51  * @author Christos KK Loverdos <loverdos@gmail.com>
52  */
53
54 object LocalFSEventStore extends Loggable {
55   private[this] final val UIDGen: UIDGenerator = EAIOUUIDGenerator
56
57   private[this] def writeToFile(file: File, data: Array[Byte]): Unit = {
58     val out = new FileOutputStream(file)
59     out.write(data)
60     out.flush()
61     out.close()
62   }
63
64   private[this] def writeToFile(file: File, data: String): Unit = {
65     writeToFile(file, makeBytes(data))
66   }
67
68   def storeResourceEvent(mc: Configurator, event: ResourceEvent, initialPayload: Array[Byte]): Unit = {
69     for(root <- mc.eventsStoreFolder) {
70       val haveEvent = event ne null
71       val uid = UIDGen.nextUID()
72
73       val occurredMDC = if(haveEvent) {
74         new MutableDateCalc(event.occurredMillis)
75       } else {
76         new MutableDateCalc(TimeHelpers.nowMillis)
77       }
78       val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
79       val rcEvents = new File(root, "rcevents")
80       rcEvents.mkdirs()
81
82       // We save two files. One containing the initial payload and one containing the transformed object.
83       val initialPayloadFile = new File(rcEvents, "rc-%s.%s.json".format(occurredString, uid))
84       writeToFile(initialPayloadFile, initialPayload)
85       logger.info("Wrote to file {}", initialPayloadFile.getCanonicalPath)
86
87       if(haveEvent) {
88         val parsedJsonFile = new File(
89           rcEvents,
90           "rc-%s-[%s]-[%s]-[%s]-[%s].%s.json".format(
91             occurredString,
92             event.id,
93             event.userId,
94             event.resource,
95             event.instanceId,
96             uid))
97
98         writeToFile(parsedJsonFile, event.toJson)
99         logger.info("Wrote to file {}", parsedJsonFile.getCanonicalPath)
100       }
101     }
102   }
103
104   def storeUserEvent(mc: Configurator, event: UserEvent, initialPayload: Array[Byte]): Unit = {
105     for(root <- mc.eventsStoreFolder) {
106       val haveEvent = event ne null
107       val uid = UIDGen.nextUID()
108
109       val occurredMDC = if(haveEvent) {
110         new MutableDateCalc(event.occurredMillis)
111       } else {
112         new MutableDateCalc(TimeHelpers.nowMillis)
113       }
114       val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
115       val imEvents = new File(root, "imevents")
116       imEvents.mkdirs()
117
118       // We save two files. One containing the initial payload and one containing the transformed object.
119       val initialPayloadFile = new File(imEvents, "im-%s.%s.json".format(occurredString, uid))
120       writeToFile(initialPayloadFile, initialPayload)
121       logger.info("Wrote to file {}", initialPayloadFile)
122
123       if(haveEvent) {
124         val parsedJsonFile = new File(
125           imEvents,
126           "im-%s-[%s]-[%s].%s.json".format(occurredString, event.id, event.userID, uid)
127         )
128
129         writeToFile(parsedJsonFile, event.toJson)
130         logger.info("Wrote to file {}", parsedJsonFile.getCanonicalPath)
131       }
132     }
133   }
134 }