2 * Copyright 2011-2012 GRNET S.A. All rights reserved.
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the following
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
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.
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.
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.
36 package gr.grnet.aquarium
38 import scala.collection.mutable.ListBuffer
39 import com.ckkloverdos.maybe.{Failed, Just, Maybe}
40 import java.nio.charset.Charset
41 import java.io.{PrintWriter, StringWriter}
42 import annotation.tailrec
48 * @author Christos KK Loverdos <loverdos@gmail.com>.
51 final val UTF_8_Charset = Charset.forName("UTF-8")
53 def tryOption[A](f: => A): Option[A] = {
56 case _: Exception => None
60 def withCloseable[C <: { def close(): Unit}, A](c: C)(f: C => A): A = {
68 def afterLastIndexOf(separator: String, input: String) = {
69 input.substring(input.lastIndexOf(separator) + 1)
72 * Compute the class name excluding any leading packages.
74 * This is basically the name after the last dot.
76 def shortNameOfClass(theClass: Class[_]): String = {
77 afterLastIndexOf(".", theClass.getName)
81 * Compute the class name excluding any leading packages and any `$` prefixes.
83 * This is basically the name after the last dot and after any dollar sign.
85 def simpleNameOfClass(theClass: Class[_]): String = {
86 afterLastIndexOf("$", shortNameOfClass(theClass))
90 * For the class of the provided object, compute the class name excluding any leading packages.
92 * This is basically the name after the last dot.
94 * The `null` value is mapped to string `"null"`.
96 def shortClassNameOf(anyRef: AnyRef): String = {
100 case clz: Class[_] =>
101 shortNameOfClass(clz)
103 shortNameOfClass(obj.getClass)
108 * Compute the class name excluding any leading packages and any `$` prefixes.
110 * This is basically the name after the last dot and after any dollar sign.
112 def simpleClassNameOf(anyRef: AnyRef) = {
113 afterLastIndexOf("$", shortClassNameOf(anyRef))
116 def safeToStringOrNull(obj: AnyRef): String = obj match {
118 case _ => obj.toString
121 def displayableObjectInfo(obj: AnyRef): String = {
122 "[%s] %s".format(obj.getClass, obj)
126 * This basically turns an [[scala.Option]] into a [[com.ckkloverdos.maybe.Maybe]] when asking a
127 * [[scala.collection.Map]] for a key.
129 * @param map The input map.
130 * @param key The key we are interested in.
131 * @tparam A The type of keys.
132 * @tparam B The type of values.
134 * @return A [[com.ckkloverdos.maybe.Just]] if a value was found, a
135 * [[com.ckkloverdos.maybe.NoVal]] if nothing was found and a
136 * [[com.ckkloverdos.maybe.Failed]] if some error happened.
139 def findFromMapAsMaybe[A, B <: AnyRef](map: scala.collection.Map[A, B], key: A): Maybe[B] = Maybe {
149 def findAndRemoveFromMap[A, B <: AnyRef](map: scala.collection.mutable.Map[A, B], key: A): Option[B] = {
153 // Dear scalac. Optimize this.
154 def nspaces(n: Int): String = {
155 ("" /: (1 to n)) ((string, _) => string + " ")
158 def rpad(s: String, size: Int) = {
159 s + nspaces((size - s.length()) max 0)
162 def maxStringSize[A](trav: Traversable[A]): Int = {
163 (0 /: trav)(_ max _.toString.length)
167 * Given a [[com.ckkloverdos.maybe.Maybe]] that is actually a [[com.ckkloverdos.maybe.Failed]], return the latter.
169 * Use this only when you are sure what the `maybe` contains, since the methods can break type safety.
175 def failedForSure[A](maybe: Maybe[A]): Failed = {
176 maybe.asInstanceOf[Failed]
180 * Given a [[com.ckkloverdos.maybe.Maybe]] that is actually a [[com.ckkloverdos.maybe.Just]], return the latter.
182 * Use this only when you are sure what the `maybe` contains, since the methods can break type safety.
188 def justForSure[A](maybe: Maybe[A]): Just[A] = {
189 maybe.asInstanceOf[Just[A]]
193 * Transform an array of bytes to a string, assuming UTF-8 encoding.
195 def makeString(bytes: Array[Byte]): String = {
196 new String(bytes, UTF_8_Charset)
200 * Transform a string to an array of bytes, following a UTF-8 decoding scheme.
202 def makeBytes(string: String): Array[Byte] = {
203 string.getBytes(UTF_8_Charset)
207 * Return the stack trace of the given [[java.lang.Throwable]] in the form of [[java.lang.String]].
212 def stringOfStackTrace(t: Throwable): String = {
213 val sw = new StringWriter()
214 val pw = new PrintWriter(sw)
216 t.printStackTrace(pw)
224 def chainOfCausesBuffer(t: Throwable): ListBuffer[String] = {
226 def loop(t: Throwable, buffer: ListBuffer[String]): ListBuffer[String] = {
232 buffer.append("%s: %s".format(shortClassNameOf(t), t.getMessage))
233 loop(t.getCause, buffer)
237 loop(t, new ListBuffer[String])
240 def chainOfCauses(t: Throwable): List[String] = {
241 chainOfCausesBuffer(t).toList
244 def sourceOfTraceElement(st: StackTraceElement): Option[String] = {
246 val path = Class.forName(st.getClassName).getProtectionDomain.getCodeSource.getLocation.getPath
247 val file = new java.io.File(path)
252 def formatTraceElement(st: StackTraceElement): String = {
253 val source = sourceOfTraceElement(st)
254 "%s.%s(%s:%s)%s".format(
259 if(source.isDefined) " [%s]".format(source.get) else ""
263 def chainOfCausesForLogging(t: Throwable, caughtTraceIndex: Int = 3) = {
264 val buf = chainOfCausesBuffer(t)
265 val happenedTrace = t.getStackTrace()(0)
266 val caughtTrace = new Exception().getStackTrace()(caughtTraceIndex)
268 buf.prepend("[Happened @] %s".format(formatTraceElement(happenedTrace)))
269 buf.prepend("[Caught @] %s".format(formatTraceElement(caughtTrace)))
271 val noNL = buf.map { line ⇒
272 "!! " + line.replaceAll("""[\n\r]+""", ", ")
278 private[this] lazy val _isRunningTests =
279 new Exception().getStackTrace().find(_.getClassName.startsWith("org.junit")).isDefined
281 def isRunningTests() = _isRunningTests