package gr.grnet.aquarium.store
import gr.grnet.aquarium.Configurator
-import com.ckkloverdos.maybe.Maybe
-import gr.grnet.aquarium.util.date.MutableDateCalc
import java.io.{FileOutputStream, File}
-import gr.grnet.aquarium.logic.events.{UserEvent, ResourceEvent}
+import gr.grnet.aquarium.util.{Loggable, stringOfStackTrace}
+import gr.grnet.aquarium.util.date.{TimeHelpers, MutableDateCalc}
+import gr.grnet.aquarium.event.model.im.IMEventModel
+import gr.grnet.aquarium.event.model.resource.ResourceEventModel
/**
* This is used whenever the property `events.store.folder` is setup in aquarium configuration.
*
- * The public methods guarantee they will not propagate any failure.
- *
* @author Christos KK Loverdos <loverdos@gmail.com>
*/
-object LocalFSEventStore {
- private[this] def writeToFile(file: File, data: Array[Byte]): Unit = {
+object LocalFSEventStore extends Loggable {
+ private[this] final val NewLine = "\n".getBytes("UTF-8")
+ private[this] final val NewLine2 = NewLine ++ NewLine
+
+ private[this] def writeToFile(file: File, data: Array[Byte], appendString: Option[String] = None): Unit = {
val out = new FileOutputStream(file)
out.write(data)
+ appendString match {
+ case Some(s) ⇒
+ out.write(NewLine2)
+ out.write(s.getBytes("UTF-8"))
+ case None ⇒
+ }
out.flush()
out.close()
+
+ logger.debug("Wrote to file {}", file.getCanonicalPath)
+ }
+
+ private[this] def createResourceEventsFolder(root: File): File = {
+ val folder = new File(root, "rc")
+ folder.mkdirs()
+ folder
+ }
+
+ private[this] def createIMEventsFolder(root: File): File = {
+ val folder = new File(root, "im")
+ folder.mkdirs()
+ folder
+ }
+
+ private[this] def writeJson(tag: String,
+ folder: File,
+ jsonPayload: Array[Byte],
+ occurredString: String,
+ extraName: Option[String],
+ isParsed: Boolean,
+ appendString: Option[String]): Unit = {
+ val file = new File(
+ folder,
+ "%s-%s%s.%s.json".format(
+ tag,
+ occurredString,
+ extraName match {
+ case Some(s) ⇒ "-" + s
+ case None ⇒ ""
+ },
+ if(isParsed) "p" else "u"
+ ))
+
+ writeToFile(file, jsonPayload, appendString)
+ }
+
+ def storeUnparsedResourceEvent(mc: Configurator, initialPayload: Array[Byte], exception: Throwable): Unit = {
+ for(root <- mc.eventsStoreFolder) {
+ val occurredMDC = new MutableDateCalc(TimeHelpers.nowMillis())
+ val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
+ val rcEventsFolder = createResourceEventsFolder(root)
+ val trace = stringOfStackTrace(exception)
+
+ writeJson("rc", rcEventsFolder, initialPayload, occurredString, None, false, Some(trace))
+ }
}
- private[this] def writeToFile(file: File, data: String): Unit = {
- writeToFile(file, data.getBytes("UTF-8"))
+ def storeResourceEvent(mc: Configurator, event: ResourceEventModel, initialPayload: Array[Byte]): Unit = {
+ require(event ne null, "Resource event must be not null")
+
+ for(root <- mc.eventsStoreFolder) {
+ val occurredMDC = new MutableDateCalc(event.occurredMillis)
+ val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
+ val rcEventsFolder = createResourceEventsFolder(root)
+
+ // Store parsed file
+ writeJson(
+ "rc",
+ rcEventsFolder,
+ initialPayload,
+ occurredString,
+ Some("[%s]-[%s]-[%s]-[%s]".format(
+ event.id,
+ event.userID,
+ event.resource,
+ event.instanceID)),
+ true,
+ None
+ )
+ }
}
- def storeResourceEvent(mc: Configurator, event: ResourceEvent, initialPayload: Array[Byte]): Maybe[Unit] = Maybe {
- if(mc.hasEventsStoreFolder) {
- val occurredString = new MutableDateCalc(event.occurredMillis).toYYYYMMDDHHMMSS
- val root = mc.eventsStoreFolder
- val rcEvents = new File(root, "rcevents")
- val parsed = event ne null
-
- // We save two files. One containing the initial payload and one containing the transformed object.
- val initialPayloadFile = new File(rcEvents, "rc-%s.raw%s".format(occurredString, if(!parsed) "x" else ""))
- Maybe { writeToFile(initialPayloadFile, initialPayload) }
-
- if(parsed) {
- val parsedJsonFile = new File(
- rcEvents,
- "rc-%s-[%s]-[%s]-[%s]-[%s].json".format(
- occurredString,
- event.id,
- event.userId,
- event.resource,
- event.instanceId))
-
- Maybe { writeToFile(parsedJsonFile, event.toJson) }
- }
+ def storeUnparsedIMEvent(mc: Configurator, initialPayload: Array[Byte], exception: Throwable): Unit = {
+ for(root <- mc.eventsStoreFolder) {
+ val occurredMDC = new MutableDateCalc(TimeHelpers.nowMillis())
+ val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
+ val imEventsFolder = createIMEventsFolder(root)
+ val trace = stringOfStackTrace(exception)
+
+ writeJson("im", imEventsFolder, initialPayload, occurredString, None, false, Some(trace))
}
}
- def storeUserEvent(mc: Configurator, event: UserEvent, initialPayload: Array[Byte]): Maybe[Unit] = Maybe {
- if(mc.hasEventsStoreFolder) {
- val occurredString = new MutableDateCalc(event.occurredMillis).toYYYYMMDDHHMMSS
- val root = mc.eventsStoreFolder
- val imEvents = new File(root, "imevents")
- val parsed = event ne null
-
- // We save two files. One containing the initial payload and one containing the transformed object.
- val initialPayloadFile = new File(imEvents, "im-%s.raw%s".format(occurredString, if(!parsed) "x" else ""))
- Maybe { writeToFile(initialPayloadFile, initialPayload) }
-
- if(parsed) {
- val parsedJsonFile = new File(imEvents, "im-%s-[%s]-[%s].json".format(occurredString, event.id, event.userID))
- Maybe { writeToFile(parsedJsonFile, event.toJson) }
- }
+ def storeIMEvent(mc: Configurator, event: IMEventModel, initialPayload: Array[Byte]): Unit = {
+ require(event ne null, "IM event must be not null")
+ for(root <- mc.eventsStoreFolder) {
+ val occurredMDC = new MutableDateCalc(event.occurredMillis)
+ val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
+ val imEventsFolder = createIMEventsFolder(root)
+
+ writeJson(
+ "im",
+ imEventsFolder,
+ initialPayload,
+ occurredString,
+ Some("[%s]-[%s]".format(event.id, event.userID)),
+ true,
+ None
+ )
}
}
}