All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scassandra.server.priming.json.PrimingJsonImplicits.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2016 Christopher Batey and Dogan Narinc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.scassandra.server.priming.json

import java.math.BigInteger
import java.net.InetAddress
import java.util.UUID

import com.typesafe.scalalogging.LazyLogging
import org.scassandra.codec.Consistency
import org.scassandra.codec.Consistency.Consistency
import org.scassandra.codec.datatype.DataType
import org.scassandra.codec.messages.BatchQueryKind.BatchQueryKind
import org.scassandra.codec.messages.BatchType.BatchType
import org.scassandra.codec.messages.{BatchQueryKind, BatchType}
import org.scassandra.cql._
import org.scassandra.server.actors._
import org.scassandra.server.priming._
import org.scassandra.server.priming.batch.{BatchPrimeSingle, BatchQueryPrime, BatchWhen}
import org.scassandra.server.priming.prepared._
import org.scassandra.server.priming.query.{PrimeCriteria, PrimeQuerySingle, Then, When}
import org.scassandra.server.priming.routes.Version
import scodec.bits.ByteVector
import spray.httpx.SprayJsonSupport
import spray.json._

import scala.collection.Set
import scala.util.{Failure, Try, Success => TSuccess}

object PrimingJsonImplicits extends DefaultJsonProtocol with SprayJsonSupport with LazyLogging {

  implicit object VariableMatchFormat extends JsonFormat[VariableMatch] {
    override def write(obj: VariableMatch): JsValue = {
      obj match {
        case ExactMatch(value) => {
          JsObject(Map(
            "type" -> JsString("exact"),
            "matcher" -> AnyJsonFormat.write(value)
          ))
        }
        case AnyMatch => JsObject(Map("type" -> JsString("any")))
      }
    }

    override def read(json: JsValue): VariableMatch = {
      json match {
        case obj: JsObject => {
          obj.fields("type") match {
            case JsString("exact") => ExactMatch(Some(AnyJsonFormat.read(obj.fields("matcher"))))
            case JsString("any") => AnyMatch
            case _ => AnyMatch
          }
        }
        case _ => AnyMatch
      }
    }
  }

  implicit object AnyJsonFormat extends JsonFormat[Any] {
    def write(x: Any) = x match {
      case n: Int => JsNumber(n)
      case n: Long => JsNumber(n)
      case short: Short => JsNumber(short)
      case byte: Byte => JsNumber(byte)
      case bd: BigDecimal => JsString(bd.bigDecimal.toPlainString)
      case s: String => JsString(s)
      case seq: Seq[_] => seqFormat[Any].write(seq)
      case m: Map[_, _] =>
        val keysAsString: Map[String, Any] = m.map({ case (k, v) => (k.toString, v)})
        mapFormat[String, Any].write(keysAsString)
      case set: Set[_] => setFormat[Any].write(set.map(s => s))
      case b: Boolean if b => JsTrue
      case b: Boolean if !b => JsFalse

      // sending as strings to not lose precision
      case double: Double => JsString(double.toString)
      case float: Float => JsString(float.toString)
      case uuid: UUID => JsString(uuid.toString)
      case bigInt: BigInt => JsNumber(bigInt)
      case bigInt: BigInteger => JsNumber(bigInt)
      case bigD: java.math.BigDecimal => JsString(bigD.toPlainString)
      case inet: InetAddress => JsString(inet.getHostAddress)
      case bytes: Array[Byte] => JsString("0x" + bytes2hex(bytes))
      case bytes: ByteVector => JsString("0x" + bytes2hex(bytes.toArray))
      case null => JsNull
      case None => JsNull
      case Some(s) => this.write(s)
      case p: Product => seqFormat[Any].write(p.productIterator.toList) // To support tuples
      case other => serializationError("Do not understand object of type " + other.getClass.getName)
    }

    def read(value: JsValue) = value match {
      case jsNumber : JsNumber => jsNumber.value
      case JsString(s) => s
      case a: JsArray => listFormat[Any].read(value)
      case o: JsObject => mapFormat[String, Any].read(value)
      case JsTrue => true
      case JsFalse => false
      case x => deserializationError("Do not understand how to deserialize " + x)
    }

    def bytes2hex(bytes: Array[Byte]): String = {
      bytes.map("%02x".format(_)).mkString
    }
  }

  implicit object ConsistencyJsonFormat extends RootJsonFormat[Consistency] {
    def write(c: Consistency) = JsString(c.toString)

    def read(value: JsValue) = value match {
      case JsString(consistency) => Consistency.withName(consistency)
      case _ => throw new IllegalArgumentException("Expected Consistency as JsString")
    }
  }

  implicit object BatchQueryKindJsonFormat extends RootJsonFormat[BatchQueryKind] {
    def write(c: BatchQueryKind) = JsString(c match {
      case BatchQueryKind.Simple => "query"
      case BatchQueryKind.Prepared => "prepared_statement"
    })

    def read(value: JsValue) = value match {
      case JsString(v) => v match {
        case "query" => BatchQueryKind.Simple
        case "prepared_statement" => BatchQueryKind.Prepared
      }
      case _ => throw new IllegalArgumentException("Expected BatchQueryKind as JsString")
    }
  }

  implicit object BatchTypeJsonFormat extends RootJsonFormat[BatchType] {
    def write(c: BatchType) = JsString(c.toString)

    def read(value: JsValue) = value match {
      case JsString(batchType) => BatchType.withName(batchType)
      case _ => throw new IllegalArgumentException("Expected BatchType as JsString")
    }
  }


  implicit object DataTypeJsonFormat extends RootJsonFormat[DataType] {

    lazy val cqlTypeFactory = new CqlTypeFactory

    def convertJavaToScalaType(javaType: CqlType): DataType = javaType match {
        // TODO: Update for UDTs when supported.
        case primitive: PrimitiveType => DataType.primitiveTypeMap(primitive.serialise())
        case map: MapType => DataType.Map(convertJavaToScalaType(map.getKeyType), convertJavaToScalaType(map.getValueType))
        case set: SetType => DataType.Set(convertJavaToScalaType(set.getType))
        case list: ListType => DataType.List(convertJavaToScalaType(list.getType))
        case tuple: TupleType => DataType.Tuple(tuple.getTypes.map(convertJavaToScalaType):_*)
    }

    def fromString(typeString: String): Try[DataType] = {
      try {
        val cqlType = cqlTypeFactory.buildType(typeString)
        TSuccess(convertJavaToScalaType(cqlType))
      } catch {
        case e: Exception => Failure(e)
      }
    }

    def write(d: DataType) = JsString(d.stringRep)

    def read(value: JsValue) = value match {
      case JsString(string) => fromString(string) match {
        case TSuccess(columnType) => columnType
        case Failure(e) =>
          logger.warn(s"Received invalid column type '$string'", e)
          throw new IllegalArgumentException(s"Not a valid column type '$string'")
      }
      case _ => throw new IllegalArgumentException("Expected ColumnType as JsString")
    }
  }

  implicit object ResultJsonFormat extends RootJsonFormat[ResultJsonRepresentation] {
    def write(result: ResultJsonRepresentation) = JsString(result.string)

    def read(value: JsValue) = value match {
      case JsString(string) => ResultJsonRepresentation.fromString(string)
      case _ => throw new IllegalArgumentException("Expected Result as JsString")
    }
  }

  implicit val impThen = jsonFormat6(Then)
  implicit val impWhen = jsonFormat5(When)
  implicit val impPrimeQueryResult = jsonFormat(PrimeQuerySingle, "when", "then")
  implicit val impConnection = jsonFormat1(Connection)
  implicit val impQuery = jsonFormat6(Query)
  implicit val impPrimeCriteria = jsonFormat3(PrimeCriteria)
  implicit val impConflictingPrimes = jsonFormat1(ConflictingPrimes)
  implicit val impTypeMismatch = jsonFormat3(TypeMismatch)
  implicit val impTypeMismatches = jsonFormat1(TypeMismatches)
  implicit val impWhenPreparedSingle = jsonFormat3(WhenPrepared)
  implicit val impThenPreparedSingle = jsonFormat6(ThenPreparedSingle)
  implicit val impPrimePreparedSingle = jsonFormat(PrimePreparedSingle, "when", "then")
  implicit val impPreparedStatementExecution = jsonFormat6(PreparedStatementExecution)
  implicit val impPreparedStatementPreparation = jsonFormat1(PreparedStatementPreparation)
  implicit val impVersion = jsonFormat1(Version)
  implicit val impBatchQuery = jsonFormat4(BatchQuery)
  implicit val impBatchExecution = jsonFormat5(BatchExecution)
  implicit val impBatchQueryPrime = jsonFormat2(BatchQueryPrime)
  implicit val impBatchWhen = jsonFormat3(BatchWhen)
  implicit val impBatchPrimeSingle = jsonFormat(BatchPrimeSingle, "when", "then")
  implicit val impClientConnection = jsonFormat2(ClientConnection)
  implicit val impClientConnections = jsonFormat1(ClientConnections)
  implicit val impClosedConnections = jsonFormat(ClosedConnections, "closed_connections", "operation")
  implicit val impAcceptNewConnectionsEnabled = jsonFormat1(AcceptNewConnectionsEnabled)
  implicit val impRejectNewConnectionsEnabled = jsonFormat1(RejectNewConnectionsEnabled)

  implicit val impCriterna = jsonFormat1(Criteria)
  implicit val impAction = jsonFormat5(Action)
  implicit val impOutcoe = jsonFormat2(Outcome)
  implicit val impPrimePreparedMultiThen = jsonFormat2(ThenPreparedMulti)
  implicit val impPrimePreparedMulti = jsonFormat(PrimePreparedMulti, "when", "then")

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy