Conditionally save events to events store folder
[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.Aquarium
39 import java.io.{FileOutputStream, File}
40 import gr.grnet.aquarium.util.{Loggable, stringOfStackTrace}
41 import gr.grnet.aquarium.util.date.{TimeHelpers, MutableDateCalc}
42 import gr.grnet.aquarium.event.model.im.IMEventModel
43 import gr.grnet.aquarium.event.model.resource.ResourceEventModel
44
45 /**
46  * This is used whenever the property `events.store.folder` is setup in aquarium configuration.
47  *
48  * @author Christos KK Loverdos <loverdos@gmail.com>
49  */
50
51 object LocalFSEventStore extends Loggable {
52   private[this] final val NewLine  = "\n".getBytes("UTF-8")
53   private[this] final val NewLine2 = NewLine ++ NewLine
54
55   private[this] def writeToFile(file: File, data: Array[Byte], appendString: Option[String] = None): Unit = {
56     val out = new FileOutputStream(file)
57     out.write(data)
58     appendString match {
59       case Some(s) ⇒
60         out.write(NewLine2)
61         out.write(s.getBytes("UTF-8"))
62       case None ⇒
63     }
64     out.flush()
65     out.close()
66
67     logger.debug("Wrote to file {}", file.getCanonicalPath)
68   }
69
70   private[this] def createResourceEventsFolder(root: File): File = {
71     val folder = new File(root, "rc")
72     folder.mkdirs()
73     folder
74   }
75
76   private[this] def createIMEventsFolder(root: File): File = {
77     val folder = new File(root, "im")
78     folder.mkdirs()
79     folder
80   }
81
82   private[this] def writeJson(tag: String,
83                               folder: File,
84                               jsonPayload: Array[Byte],
85                               occurredString: String,
86                               extraName: Option[String],
87                               isParsed: Boolean,
88                               appendString: Option[String]): Unit = {
89     val file = new File(
90       folder,
91       "%s-%s%s.%s.json".format(
92         tag,
93         occurredString,
94         extraName match {
95           case Some(s) ⇒ "-" + s
96           case None    ⇒ ""
97         },
98         if(isParsed) "p" else "u"
99       ))
100
101     writeToFile(file, jsonPayload, appendString)
102   }
103
104   def storeUnparsedResourceEvent(aquarium: Aquarium, initialPayload: Array[Byte], exception: Throwable): Unit = {
105     for(root <- aquarium.eventsStoreFolder) {
106       val occurredMDC = new MutableDateCalc(TimeHelpers.nowMillis())
107       val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
108       val rcEventsFolder = createResourceEventsFolder(root)
109       val trace = stringOfStackTrace(exception)
110
111       writeJson("rc", rcEventsFolder, initialPayload, occurredString, None, false, Some(trace))
112     }
113   }
114
115   def storeResourceEvent(aquarium: Aquarium, event: ResourceEventModel, initialPayload: Array[Byte]): Unit = {
116     if(!aquarium.saveResourceEventsToEventsStoreFolder) {
117       return
118     }
119
120     require(event ne null, "Resource event must be not null")
121
122     for(root <- aquarium.eventsStoreFolder) {
123       val occurredMDC = new MutableDateCalc(event.occurredMillis)
124       val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
125       val rcEventsFolder = createResourceEventsFolder(root)
126
127       // Store parsed file
128       writeJson(
129         "rc",
130         rcEventsFolder,
131         initialPayload,
132         occurredString,
133         Some("[%s]-[%s]-[%s]-[%s]".format(
134           event.id,
135           event.userID,
136           event.resource,
137           event.instanceID)),
138         true,
139         None
140       )
141     }
142   }
143
144   def storeUnparsedIMEvent(aquarium: Aquarium, initialPayload: Array[Byte], exception: Throwable): Unit = {
145     for(root <- aquarium.eventsStoreFolder) {
146       val occurredMDC = new MutableDateCalc(TimeHelpers.nowMillis())
147       val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
148       val imEventsFolder = createIMEventsFolder(root)
149       val trace = stringOfStackTrace(exception)
150
151       writeJson("im", imEventsFolder, initialPayload, occurredString, None, false, Some(trace))
152     }
153   }
154
155   def storeIMEvent(aquarium: Aquarium, event: IMEventModel, initialPayload: Array[Byte]): Unit = {
156     if(!aquarium.saveIMEventsToEventsStoreFolder) {
157       return
158     }
159
160     require(event ne null, "IM event must be not null")
161
162     for(root <- aquarium.eventsStoreFolder) {
163       val occurredMDC = new MutableDateCalc(event.occurredMillis)
164       val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
165       val imEventsFolder = createIMEventsFolder(root)
166
167       writeJson(
168         "im",
169         imEventsFolder,
170         initialPayload,
171         occurredString,
172         Some("[%s]-[%s]".format(event.id, event.userID)),
173         true,
174         None
175       )
176     }
177   }
178 }