├── conf └── env.test │ ├── .gitignore │ └── logback.xml ├── version.sbt ├── AUTHORS ├── .gitignore ├── project ├── build.properties └── plugins.sbt ├── framework ├── ixias-core │ └── src │ │ ├── main │ │ └── scala │ │ │ └── ixias │ │ │ ├── persistence │ │ │ ├── lifted │ │ │ │ ├── ExtensionMethods.scala │ │ │ │ ├── Aliases.scala │ │ │ │ ├── ConverterOps.scala │ │ │ │ ├── SlickRepOps.scala │ │ │ │ ├── SlickDBIOActionOps.scala │ │ │ │ ├── SlickRepUnsafeOps.scala │ │ │ │ ├── SlickQueryOps.scala │ │ │ │ └── SlickColumnOptionOps.scala │ │ │ ├── dbio │ │ │ │ ├── IOAction.scala │ │ │ │ ├── EntityIOAction.scala │ │ │ │ └── Execution.scala │ │ │ ├── action │ │ │ │ ├── BasicAction.scala │ │ │ │ ├── ShadeDBAction.scala │ │ │ │ └── SlickDBAction.scala │ │ │ ├── backend │ │ │ │ ├── BasicDatabaseContainer.scala │ │ │ │ ├── BasicBackend.scala │ │ │ │ ├── SlickJdbcUrlBuilderForRedshift.scala │ │ │ │ ├── SlickJdbcUrlBuilderForMySQL.scala │ │ │ │ ├── SlickJdbcUrlBuilder.scala │ │ │ │ ├── ShadeConfig.scala │ │ │ │ ├── ShadeBackend.scala │ │ │ │ ├── SlickConfig.scala │ │ │ │ ├── SlickBackend.scala │ │ │ │ └── BasicDatabaseConfig.scala │ │ │ ├── model │ │ │ │ ├── Cursor.scala │ │ │ │ ├── DataSourceName.scala │ │ │ │ ├── Converter.scala │ │ │ │ └── Table.scala │ │ │ ├── Repository.scala │ │ │ ├── util │ │ │ │ └── SlickToolProvider.scala │ │ │ └── SlickRepository.scala │ │ │ ├── file │ │ │ └── csv │ │ │ │ ├── QuoteStyle.scala │ │ │ │ └── CsvFormat.scala │ │ │ ├── model │ │ │ ├── Identity.scala │ │ │ ├── package.scala │ │ │ ├── EntityModel.scala │ │ │ └── Entity.scala │ │ │ ├── security │ │ │ ├── TokenGenerator.scala │ │ │ ├── Token.scala │ │ │ ├── TokenSigner.scala │ │ │ └── KeyReader.scala │ │ │ └── util │ │ │ ├── ChainSyntax.scala │ │ │ ├── PolyLeftJoinSyntax.scala │ │ │ ├── LabelledGenericMerger.scala │ │ │ ├── OrderingHelper.scala │ │ │ ├── Logging.scala │ │ │ └── json │ │ │ ├── JsonEnvWrites.scala │ │ │ └── JsonEnvReads.scala │ │ └── test │ │ └── scala │ │ └── ixias │ │ └── persistence │ │ └── backend │ │ └── BasicDatabaseContainerTest.scala ├── ixias-play-scalate │ └── src │ │ └── main │ │ └── scala │ │ └── ixias │ │ └── play │ │ └── api │ │ └── scalate │ │ └── mvc │ │ ├── ScalateExtensionMethods.scala │ │ ├── JadeCompilationException.scala │ │ └── JadeHelper.scala ├── ixias-aws-qldb │ └── src │ │ └── main │ │ └── scala │ │ └── ixias │ │ └── aws │ │ └── qldb │ │ ├── databind │ │ ├── DatabindModule.scala │ │ ├── EnumStatusSerializerModule.scala │ │ ├── EnumStatusDeserializerModule.scala │ │ ├── EnumBitFlagsSerializerModule.scala │ │ └── EnumBitFlagsDeserializerModule.scala │ │ ├── model │ │ ├── SqlResultContainer.scala │ │ ├── Document.scala │ │ ├── Table.scala │ │ ├── SqlPrepareStatement.scala │ │ ├── TableQuery.scala │ │ ├── SqlStatement.scala │ │ └── ConvOps.scala │ │ ├── dbio │ │ └── DBIOAction.scala │ │ ├── AmazonQLDB.scala │ │ └── backend │ │ ├── AmazonQLDBAction.scala │ │ ├── AmazonQLDBConfig.scala │ │ └── AmazonQLDBBackend.scala ├── ixias-aws-s3 │ └── src │ │ └── main │ │ └── scala │ │ └── ixias │ │ └── aws │ │ └── s3 │ │ ├── persistence │ │ ├── SlickResource.scala │ │ └── File.scala │ │ ├── model │ │ ├── FileResource.scala │ │ ├── FileSilo.scala │ │ ├── CloudFrontUrl.scala │ │ └── FileBuilder.scala │ │ └── backend │ │ └── DataSourceName.scala ├── ixias-play-core │ └── src │ │ └── main │ │ └── scala │ │ └── ixias │ │ └── play │ │ └── api │ │ ├── mvc │ │ ├── Binders.scala │ │ ├── binder │ │ │ ├── Box.scala │ │ │ ├── Cursor.scala │ │ │ ├── JavaTime.scala │ │ │ └── Id.scala │ │ ├── JsonHelper.scala │ │ ├── FormHelper.scala │ │ ├── BaseExtensionMethods.scala │ │ ├── Errors.scala │ │ ├── DeviceDetection.scala │ │ ├── QueryStringHelper.scala │ │ └── RequestHeaderAttrHelper.scala │ │ ├── json │ │ ├── JsValueError.scala │ │ ├── YearMonthWrites.scala │ │ └── YearMonthReads.scala │ │ └── controllers │ │ └── UIAssets.scala ├── ixias-play-auth │ └── src │ │ └── main │ │ └── scala │ │ └── ixias │ │ └── play │ │ └── api │ │ └── auth │ │ ├── mvc │ │ ├── AuthExtensionMethods.scala │ │ ├── Authenticated.scala │ │ ├── AuthenticatedOrNot.scala │ │ └── Authorized.scala │ │ ├── token │ │ ├── TokenViaHttpHeader.scala │ │ ├── TokenViaSession.scala │ │ └── Token.scala │ │ └── container │ │ └── Container.scala ├── ixias-aws-sns │ └── src │ │ └── main │ │ └── scala │ │ └── ixias │ │ └── aws │ │ └── sns │ │ ├── backend │ │ ├── DataSourceName.scala │ │ ├── AmazonSNSBackend.scala │ │ └── AmazonSNSConfig.scala │ │ └── AmazonSNS.scala └── ixias-mail │ └── src │ └── main │ └── scala │ └── ixias │ ├── EmailClient.scala │ ├── EmailClientViaTwillio.scala │ └── EmailTemplate.scala ├── README.md └── LICENSE /conf/env.test/.gitignore: -------------------------------------------------------------------------------- 1 | application.conf 2 | -------------------------------------------------------------------------------- /version.sbt: -------------------------------------------------------------------------------- 1 | version in ThisBuild := "1.1.50-SNAPSHOT" 2 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Yoshinobu Kinugasa 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /RUNNING_PID 2 | /logs/ 3 | /.idea 4 | /.idea_modules 5 | /project/*-shim.sbt 6 | /project/project/ 7 | /project/target/ 8 | /target/ 9 | /framework/*/target 10 | backup 11 | .metals 12 | .bloop 13 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the nextbeat services. 3 | * 4 | * For the full copyright and license information, 5 | * please view the LICENSE file that was distributed with this source code. 6 | */ 7 | 8 | sbt.version = 1.3.3 9 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/lifted/ExtensionMethods.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.lifted 10 | 11 | trait ExtensionMethods extends ConverterOps 12 | -------------------------------------------------------------------------------- /framework/ixias-play-scalate/src/main/scala/ixias/play/api/scalate/mvc/ScalateExtensionMethods.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.scalate.mvc 10 | 11 | trait ScalateExtensionMethods { 12 | val JadeHelper = ixias.play.api.scalate.mvc.JadeHelper 13 | } 14 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the nextbeat services. 3 | * 4 | * For the full copyright and license information, 5 | * please view the LICENSE file that was distributed with this source code. 6 | */ 7 | 8 | 9 | addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.3.15") 10 | addSbtPlugin("com.scalapenos" % "sbt-prompt" % "1.0.2") 11 | addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.7") 12 | addSbtPlugin("com.frugalmechanic" % "fm-sbt-s3-resolver" % "0.19.0") 13 | -------------------------------------------------------------------------------- /conf/env.test/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %date{yyyy-MM-dd HH:mm:ss} [%thread] %level %logger - %msg \(%file:%line\)%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/lifted/Aliases.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.lifted 10 | 11 | /** 12 | * Aliases for lifted embedding features. This trait can be mixed into aliasing 13 | * objects which simplify the use of the lifted embedding. 14 | */ 15 | trait Aliases 16 | { 17 | val Cursor = ixias.persistence.model.Cursor 18 | type Cursor = ixias.persistence.model.Cursor 19 | } 20 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/file/csv/QuoteStyle.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.file.csv 10 | 11 | import ixias.util.Enum 12 | 13 | sealed abstract class QuoteStyle extends Enum 14 | object QuoteStyle extends Enum.Of[QuoteStyle] { 15 | case object NONE extends QuoteStyle 16 | case object MINIMAL extends QuoteStyle 17 | case object NONE_NUMERIC extends QuoteStyle 18 | case object ALL extends QuoteStyle 19 | } 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IxiaS 2 | 3 | IxiaS is a development platform using scala languages. 4 | 5 | # Getting Started 6 | 7 | Just add IxiaS, a JDBC driver, and a slf4j implementation to your sbt build settings: 8 | 9 | ``` scala 10 | resolvers ++= Seq( 11 | "IxiaS Releases" at "http://maven.ixias.net.s3-ap-northeast-1.amazonaws.com/releases" 12 | ) 13 | 14 | libraryDependencies ++= Seq( 15 | "net.ixias" %% "ixias" % "1.1.11", 16 | "net.ixias" %% "ixias-aws" % "1.1.11", 17 | "net.ixias" %% "ixias-play" % "1.1.11", 18 | "mysql" % "mysql-connector-java" % "5.1.+", 19 | "ch.qos.logback" % "logback-classic" % "1.1.+" 20 | ) 21 | ``` 22 | 23 | # NOTE 24 | 25 | The quick start document is not ready. coming soon... 26 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/databind/DatabindModule.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.databind 10 | 11 | import com.fasterxml.jackson.module.scala.JacksonModule 12 | 13 | object DatabindModule extends JacksonModule 14 | with EnumBitFlagsSerializerModule 15 | with EnumBitFlagsDeserializerModule 16 | with EnumStatusSerializerModule 17 | with EnumStatusDeserializerModule 18 | { 19 | override def getModuleName = "DatabindModule" 20 | } 21 | -------------------------------------------------------------------------------- /framework/ixias-aws-s3/src/main/scala/ixias/aws/s3/persistence/SlickResource.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.s3.persistence 10 | 11 | import slick.jdbc.JdbcProfile 12 | import ixias.aws.s3.backend.DataSourceName 13 | 14 | trait SlickResource[P <: JdbcProfile] { 15 | 16 | implicit val driver: P 17 | 18 | implicit val dsn: DataSourceName 19 | 20 | // --[ Tables ] -------------------------------------------------------------- 21 | object FileTable extends FileTable 22 | lazy val AllTables = Seq(FileTable) 23 | } 24 | -------------------------------------------------------------------------------- /framework/ixias-play-scalate/src/main/scala/ixias/play/api/scalate/mvc/JadeCompilationException.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.scalate.mvc 10 | 11 | import play.api.PlayException 12 | 13 | final class JadeCompilationException( 14 | override val sourceName: String, 15 | override val input: String, 16 | override val line: Integer, 17 | override val position: Integer, 18 | message: String, 19 | cause: Throwable 20 | ) extends PlayException.ExceptionSource("scalate compilation exception", message, cause) 21 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/dbio/IOAction.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.dbio 10 | 11 | import scala.concurrent.Future 12 | 13 | /** 14 | * A Persistence I/O Action that can be executed on a database. 15 | */ 16 | trait IOAction { 17 | 18 | /** Construct a success validation value. */ 19 | protected def successful[T](value: T): Future[T] = 20 | Future.successful(value) 21 | 22 | /** Construct a failure validation value. */ 23 | protected def failed[T](exception: Throwable): Future[T] = 24 | Future.failed(exception) 25 | } 26 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/action/BasicAction.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.action 10 | 11 | import scala.concurrent.Future 12 | 13 | /** 14 | * A builder for generic DB Actions that generalizes over the type of requests. 15 | */ 16 | trait BasicActionFunction[-R, +T] { 17 | 18 | /** 19 | * Invoke the block. 20 | * This is the main method that an ActionBuilder has to implement. 21 | */ 22 | def invokeBlock[A](request: R, block: T => Future[A]): Future[A] 23 | } 24 | 25 | trait BasicAction[-R, +T] extends BasicActionFunction[R, T] 26 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/model/Identity.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.model 10 | 11 | import shapeless.Unwrapped 12 | 13 | /** The Identity of Entity */ 14 | trait Identity[T] { 15 | type U 16 | def apply(u: U): T 17 | def unwrap(t: T): U 18 | } 19 | 20 | object Identity { 21 | type Aux[T, U0] = Identity[T] { type U = U0 } 22 | implicit def unwrappedIdentity[W, U0](implicit uw: Unwrapped.Aux[W, U0]): Identity.Aux[W, U0] = 23 | new Identity[W] { 24 | type U = U0 25 | def apply(u: U): W = uw.wrap(u) 26 | def unwrap(w: W): U = uw.unwrap(w) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/mvc/Binders.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.mvc 10 | 11 | /** 12 | * Custom binders for Path, and Query String 13 | * 14 | * If you provide your own PathBindable or QueryStringBindable, 15 | * make sure PlayFramework knows to import them 16 | * in your routes file by using the routesImport SBT settings key. 17 | * 18 | * [ Hint ] 19 | * RoutesKeys.routesImport := Seq("CustomBinder._") 20 | */ 21 | trait Binders extends binder.Box 22 | with binder.IdBindable 23 | with binder.CursorBindable 24 | with binder.JavaTimeBindable 25 | 26 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/json/JsValueError.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.json 10 | 11 | import play.api.libs.json._ 12 | import play.api.libs.functional.syntax._ 13 | 14 | // The Error response 15 | //~~~~~~~~~~~~~~~~~~~~ 16 | case class JsValueError( 17 | val error: Int, // Error code 18 | val message: Option[String] // Error message 19 | ) 20 | 21 | object JsValueError { 22 | implicit val writes: Writes[JsValueError] = ( 23 | (__ \ "error" ).write[Int] and 24 | (__ \ "message").write[Option[String]] 25 | )(unlift(JsValueError.unapply)) 26 | } 27 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/model/SqlResultContainer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.model 10 | 11 | /** 12 | * Container definition with original execution result and conversion information 13 | */ 14 | trait SqlResultContainer { 15 | 16 | /** 17 | * Type of model of mapping destination 18 | */ 19 | type Model 20 | 21 | /** 22 | * Type of Result 23 | */ 24 | type Result 25 | 26 | /** 27 | * Get result value. 28 | */ 29 | def value: Result 30 | 31 | /** 32 | * Raw results of Amazon QLDB 33 | */ 34 | val data: software.amazon.qldb.Result 35 | } 36 | 37 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/model/Document.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.model 10 | 11 | import ixias.model._ 12 | 13 | // Affected document infomation 14 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 15 | case class AffectedDocument( 16 | documentId: AffectedDocument.Id 17 | ) 18 | 19 | object AffectedDocument { 20 | type Id = Document.Id[AffectedDocument] 21 | val Id = the[Identity[Id]] 22 | } 23 | 24 | // typedef for Document 25 | //~~~~~~~~~~~~~~~~~~~~~~ 26 | trait Document 27 | object Document { 28 | 29 | /** 30 | * Provide definition of Document-Id 31 | */ 32 | type Id[T] = String @@ (Document, T) 33 | } 34 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/security/TokenGenerator.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.security 10 | 11 | import java.security.SecureRandom 12 | import scala.util.Random 13 | 14 | /** 15 | * The generator to generate a new token as string 16 | */ 17 | case class TokenGenerator( 18 | protected val table: String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", 19 | protected val random: Random = new Random(new SecureRandom()) 20 | ) { 21 | 22 | /** 23 | * Generate a new token as string 24 | */ 25 | final def next(length: Int): String = 26 | Iterator.continually( 27 | random.nextInt(table.size)).map(table).take(length).mkString 28 | } 29 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/file/csv/CsvFormat.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.file.csv 10 | 11 | trait CsvFormat 12 | { 13 | val ASCII_NULL = 0x00 14 | val ASCII_HTAB = 0x09 15 | val ASCII_VTAB = 0x0B 16 | val ASCII_LINE_FEED = 0x0A 17 | val ASCII_CARRIAGE_RETURN = 0x0D 18 | val ASCII_SPACE = 0x20 19 | 20 | val CSV_FIELD_TERM_CHAR = '\t' 21 | val CSV_ENCLOSED_CHAR = '"' 22 | val CSV_ESCAPED_CHAR = '\\' 23 | 24 | val CSV_WRITE_LINE_TERM = "\r\n" 25 | val CSV_WRITE_QUOTE_STYLE: QuoteStyle = QuoteStyle.NONE_NUMERIC 26 | val CSV_WRITE_MINIMAL_QUOTE_SPECS = Seq( 27 | '\r', 28 | '\n', 29 | CSV_FIELD_TERM_CHAR, 30 | CSV_ENCLOSED_CHAR 31 | ) 32 | } 33 | 34 | object CsvDefaultFormat extends CsvFormat 35 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/util/ChainSyntax.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.util 10 | 11 | import scala.language.implicitConversions 12 | 13 | /** 14 | * Provides tap/pipe functions for chaining methods 15 | * Officially supported since Scala 2.13. 16 | */ 17 | final class ChainSyntaxOps[A](private val self: A) extends AnyVal { 18 | 19 | /** 20 | * As a side effect, the value is passed to the function, 21 | * and the original value is returned after the function is executed. 22 | */ 23 | def tap[U](f: A => U): A = { 24 | f(self) 25 | self 26 | } 27 | 28 | /** 29 | * Transform a value by applying the function 30 | */ 31 | def pipe[B](f: A => B): B = 32 | f(self) 33 | } 34 | 35 | trait ChainSyntax { 36 | implicit final def toChainSyntaxOps[T](v: T): ChainSyntaxOps[T] = 37 | new ChainSyntaxOps(v) 38 | } 39 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/json/YearMonthWrites.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.json 10 | 11 | import java.time.YearMonth 12 | import java.time.format.DateTimeFormatter 13 | import play.api.libs.json.EnvWrites 14 | import scala.language.implicitConversions 15 | 16 | object YearMonthWrites extends EnvWrites { 17 | 18 | /** Formatting */ 19 | implicit def DefaultYearMonthFormatter(formatter: DateTimeFormatter) = 20 | new TemporalFormatter[YearMonth] { 21 | def format(temporal: YearMonth): String = { 22 | formatter.format(temporal) 23 | } 24 | } 25 | 26 | /** 27 | * The default typeclass to write a `java.time.YearMonth`, 28 | */ 29 | implicit val writesYearMonth = 30 | temporalWrites[YearMonth, DateTimeFormatter]( 31 | DateTimeFormatter.ofPattern("yyyy-MM") 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/model/package.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias 10 | 11 | package object model { 12 | 13 | /** Tagged with `U` as representation type and added a tag. */ 14 | object tag { 15 | def apply[U] = new shapeless.tag.Tagger[U] 16 | } 17 | type @@[+T, U] = shapeless.tag.@@[T, U] 18 | 19 | /** 20 | * Used as a term `the[T]` yields the unique implicit value of type `T` in the current 21 | * implicit scope, if any. It is a compile time error if there is no such value. Its 22 | * primary advantage over `Predef.implicitly` is that it will preserve any refinement that 23 | * the implicit definition has, resulting in more precisely typed, and hence often more 24 | * useful, values, 25 | */ 26 | val the = shapeless.the 27 | 28 | /** The current time */ 29 | def NOW = java.time.LocalDateTime.now() 30 | } 31 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/mvc/binder/Box.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.mvc.binder 10 | 11 | import scala.language.implicitConversions 12 | 13 | trait Box { 14 | 15 | /** 16 | * Tagged type path parameter can't be used in route specifications: 17 | * 18 | * Example route: GET /:id controllers.HomeController.testId(id: Id) 19 | * Compile error: class type required but Long with Tagged[IdTag] found. 20 | * 21 | * A solution to this problem is to wrap the tagged type parameter in a Function0[A] 22 | */ 23 | type Box[A] = () => A 24 | type BoxCsv[A] = () => Seq[A] 25 | 26 | implicit def toBase[A](box: Box[A]): A = box() 27 | implicit def toBase[A](box: BoxCsv[A]): Seq[A] = box() 28 | implicit def toBaseOpt[A](box: Option[Box[A]]): Option[A] = box.map(_()) 29 | } 30 | 31 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/backend/BasicDatabaseContainer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.backend 10 | 11 | import java.util.concurrent.ConcurrentHashMap 12 | 13 | import scala.concurrent.Future 14 | import ixias.persistence.model.DataSourceName 15 | 16 | 17 | /** 18 | * The container to manage databse base associated with DSN 19 | */ 20 | trait BasicDatabaseContainer[T] { 21 | 22 | /** Shared store */ 23 | protected var cache = new ConcurrentHashMap[DataSourceName, Future[T]]() 24 | 25 | /** 26 | * If given DSN is already in this map, returns associated data souce. 27 | * Otherwise, computes value from given expression `op`, stores with key 28 | * in map and returns that value. 29 | */ 30 | def getOrElseUpdate(op: => Future[T])(implicit dsn: DataSourceName): Future[T] = 31 | cache.computeIfAbsent(dsn, _ => op) 32 | } 33 | -------------------------------------------------------------------------------- /framework/ixias-play-auth/src/main/scala/ixias/play/api/auth/mvc/AuthExtensionMethods.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.auth.mvc 10 | 11 | import play.api.mvc._ 12 | import ixias.play.api.mvc.BaseExtensionMethods 13 | 14 | trait AuthExtensionMethods extends BaseExtensionMethods { self: BaseControllerHelpers => 15 | 16 | // For authentication 17 | def Authenticated(auth: AuthProfile[_, _, _]): ActionBuilder[Request, AnyContent] = 18 | AuthenticatedActionBuilder(auth, parse.default) 19 | 20 | // For authentication or not. 21 | def AuthenticatedOrNot(auth: AuthProfile[_, _, _]): ActionBuilder[Request, AnyContent] = 22 | AuthenticatedOrNotActionBuilder(auth, parse.default) 23 | 24 | // For authorization 25 | def Authorized[T](auth: AuthProfile[_, _, T], authority: Option[T]): ActionBuilder[Request, AnyContent] = 26 | AuthorizedActionBuilder(auth, authority, parse.default) 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2015-2018 ixias.net. http://ixias.net 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/backend/BasicBackend.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.backend 10 | 11 | import scala.concurrent.Future 12 | import ixias.persistence.model.DataSourceName 13 | import ixias.persistence.dbio.Execution 14 | import ixias.util.Logger 15 | import org.slf4j.LoggerFactory 16 | 17 | /** 18 | * The backend to handle the database and session. 19 | */ 20 | trait BasicBackend[T] extends BasicDatabaseConfig { 21 | 22 | /** The type of database used by this backend. */ 23 | type Database = T 24 | 25 | /** The Execution Context */ 26 | protected implicit val ctx = Execution.Implicits.trampoline 27 | 28 | /** The logger for profile */ 29 | protected lazy val logger = 30 | new Logger(LoggerFactory.getLogger(this.getClass.getName)) 31 | 32 | /** Get a Database instance from connection pool. */ 33 | def getDatabase(implicit dsn: DataSourceName): Future[T] 34 | } 35 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/lifted/ConverterOps.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.lifted 10 | 11 | import ixias.model._ 12 | import ixias.persistence.model.Converter 13 | import scala.language.implicitConversions 14 | 15 | trait ConverterOps 16 | { 17 | // for EntityModel 18 | implicit def toModelToEntity[K <: @@[_, _], M <: EntityModel[K]] 19 | (m: M): Entity.EmbeddedId[K, M] = Entity.EmbeddedId[K, M](m) 20 | 21 | // for Seq[EntityModel] 22 | implicit def toModelToEntitySeq[K <: @@[_, _], M <: EntityModel[K]] 23 | (m: Seq[M]): Seq[Entity.EmbeddedId[K, M]] = m.map(Entity.EmbeddedId[K, M](_)) 24 | 25 | // for Option[EntityModel] 26 | implicit def toModelToEntityOpt[K <: @@[_, _], M <: EntityModel[K]] 27 | (m: Option[M]): Option[Entity.EmbeddedId[K, M]] = m.map(Entity.EmbeddedId[K, M](_)) 28 | 29 | implicit def convert[A, B](o: A)(implicit conv: Converter[A, B]): B = conv.convert(o) 30 | } 31 | -------------------------------------------------------------------------------- /framework/ixias-aws-s3/src/main/scala/ixias/aws/s3/model/FileResource.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.s3.model 10 | 11 | import ixias.model.Entity 12 | 13 | // The type of file resource. 14 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 15 | case class FileResource( 16 | fid: File.Id, 17 | content: Option[File] 18 | ) { 19 | def join(file: Option[File.EmbeddedId]): FileResource = 20 | this.copy(content = file.collect { 21 | case e if e.id == this.fid => e.v 22 | }) 23 | 24 | def join(candidates: Seq[File.EmbeddedId]): FileResource = 25 | this.copy(content = candidates.collectFirst { 26 | case e if e.id == this.fid => e.v 27 | }) 28 | } 29 | 30 | // The companion object 31 | //~~~~~~~~~~~~~~~~~~~~~~ 32 | object FileResource { 33 | def apply(fid: File.Id) = new FileResource(fid, None) 34 | def apply(file: Entity.EmbeddedId[File.Id, File]) = new FileResource(file.id, Some(file.v)) 35 | } 36 | 37 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/lifted/SlickRepOps.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.lifted 10 | 11 | import slick.lifted.Rep 12 | import slick.jdbc.JdbcProfile 13 | import slick.ast.Library.SqlOperator 14 | import scala.language.implicitConversions 15 | 16 | trait SlickRepOps[P <: JdbcProfile] { 17 | val driver: P 18 | implicit def bitwiseColumnExtensionMethods[B1](c: Rep[B1]) = 19 | new BaseBitwiseColumnExtensionMethods[B1](c) 20 | } 21 | 22 | // Bitwise operators 23 | //~~~~~~~~~~~~~~~~~~~ 24 | trait BitwiseColumnExtensionMethods[B1, P1] extends Any with slick.lifted.ExtensionMethods[B1, P1] { 25 | def & [P2, R](e: Rep[P2])(implicit om: o#arg[B1, P2]#to[B1, R]) = 26 | om.column(new SqlOperator("&"), n, e.toNode) 27 | } 28 | final class BaseBitwiseColumnExtensionMethods[P1](val c: Rep[P1]) extends AnyVal 29 | with BitwiseColumnExtensionMethods[P1, P1] 30 | with slick.lifted.BaseExtensionMethods[P1] 31 | 32 | -------------------------------------------------------------------------------- /framework/ixias-aws-s3/src/main/scala/ixias/aws/s3/backend/DataSourceName.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.s3.backend 10 | 11 | /** 12 | * The DSN(Data-Source-Name) structure. 13 | */ 14 | sealed class DataSourceName( 15 | val path: String, 16 | val resource: String, 17 | val name: Option[String] 18 | ) 19 | 20 | // Conpanion object. 21 | //~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | object DataSourceName { 23 | 24 | /** The synatx format for DSN */ 25 | val SYNTAX_DATA_SOURCE_NAME1 = """^(ixias.aws.s3)://(\w+?)$""".r 26 | val SYNTAX_DATA_SOURCE_NAME2 = """^(ixias.aws.s3)://(\w+?)/(\w+)$""".r 27 | 28 | /** Build a `DataSourceName` object. */ 29 | def apply(dsn: String) = dsn match { 30 | case SYNTAX_DATA_SOURCE_NAME1(p1, p2) => new DataSourceName(p1, p2, None) 31 | case SYNTAX_DATA_SOURCE_NAME2(p1, p2, p3) => new DataSourceName(p1, p2, Some(p3)) 32 | case _ => throw new Exception(s"""Dose not match the DSN format. ($dsn)""") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/backend/SlickJdbcUrlBuilderForRedshift.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.backend 10 | 11 | import scala.util.Try 12 | import ixias.persistence.model.DataSourceName 13 | 14 | /** 15 | * Build a JDBC-Url for Redshift. 16 | */ 17 | class SlickJdbcUrlBuilderForRedshift extends SlickJdbcUrlBuilder with BasicDatabaseConfig { 18 | 19 | // --[ Properties ]----------------------------------------------------------- 20 | val FMT_URL_DEFALT = """jdbc:postgresql://%s/%s?currentSchema=%s""" 21 | 22 | // --[ Methods ]-------------------------------------------------------------- 23 | /** 24 | * Generate a url for JDBC connection resouce. 25 | */ 26 | def buildUrl(implicit dsn: DataSourceName): Try[String] = 27 | for { 28 | hosts <- getHosts 29 | database <- getDatabaseName 30 | } yield { 31 | FMT_URL_DEFALT.format(hosts.mkString(","), database, getSchemaName) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /framework/ixias-aws-sns/src/main/scala/ixias/aws/sns/backend/DataSourceName.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.sns.backend 10 | 11 | /** 12 | * The DSN(Data-Source-Name) structure. 13 | */ 14 | sealed class DataSourceName( 15 | val path: String, 16 | val resource: String, 17 | val name: Option[String] 18 | ) 19 | 20 | // Conpanion object. 21 | //~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | object DataSourceName { 23 | 24 | /** The synatx format for DSN */ 25 | val SYNTAX_DATA_SOURCE_NAME1 = """^(ixias.aws.sns)://(\w+?)$""".r 26 | val SYNTAX_DATA_SOURCE_NAME2 = """^(ixias.aws.sns)://(\w+?)/(\w+)$$""".r 27 | 28 | /** Build a `DataSourceName` object. */ 29 | def apply(dsn: String) = dsn match { 30 | case SYNTAX_DATA_SOURCE_NAME1(p1, p2) => new DataSourceName(p1, p2, None) 31 | case SYNTAX_DATA_SOURCE_NAME2(p1, p2, p3) => new DataSourceName(p1, p2, Some(p3)) 32 | case _ => throw new Exception(s"""Dose not match the DSN format. ($dsn)""") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/action/ShadeDBAction.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.action 10 | 11 | import scala.util.Failure 12 | import scala.concurrent.Future 13 | 14 | import ixias.persistence.ShadeProfile 15 | import ixias.persistence.model.DataSourceName 16 | 17 | /** 18 | * The provider for `ShadeDBAction` 19 | */ 20 | trait ShadeDBActionProvider { self: ShadeProfile => 21 | 22 | object ShadeDBAction extends BasicAction[DataSourceName, Database] { 23 | 24 | /** Invoke DB action block. */ 25 | def apply[A](dsn: DataSourceName)(block: Database => Future[A]): Future[A] = 26 | invokeBlock(dsn, block) 27 | 28 | /** Run block process */ 29 | def invokeBlock[A](dsn: DataSourceName, block: Database => Future[A]): Future[A] = 30 | (for { 31 | db <- backend.getDatabase(dsn) 32 | value <- block(db) 33 | } yield value) andThen { 34 | case Failure(ex) => logger.error( 35 | "The database action failed. dsn=%s".format(dsn.toString), ex) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/model/EntityModel.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.model 10 | 11 | import java.time.LocalDateTime 12 | 13 | /** 14 | * The definition for projecting domain model of DDD 15 | */ 16 | trait EntityModel[K <: @@[_, _]] extends Serializable { 17 | 18 | /** The type of entity id */ 19 | type Id = K 20 | type WithNoId = Entity.WithNoId [Id, this.type] 21 | type EmbeddedId = Entity.EmbeddedId[Id, this.type] 22 | 23 | /** The entity's identity. */ 24 | val id: Option[Id] 25 | 26 | /** The date and time when this entity was last updated. */ 27 | val updatedAt: LocalDateTime 28 | 29 | /** The date and time when this entity was added to the system. */ 30 | val createdAt: LocalDateTime 31 | 32 | /** convet to a Entiry object. */ 33 | def toWithNoId: WithNoId = Entity.WithNoId(this) 34 | def toEmbeddedId: EmbeddedId = Entity.EmbeddedId(this) 35 | } 36 | 37 | trait EntityModelWithNoTimeRec[K <: @@[_, _]] extends EntityModel[K] { 38 | val updatedAt: LocalDateTime = null 39 | val createdAt: LocalDateTime = null 40 | } 41 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/backend/SlickJdbcUrlBuilderForMySQL.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.backend 10 | 11 | import scala.util.Try 12 | import ixias.persistence.model.DataSourceName 13 | 14 | /** 15 | * Build a JDBC-Url for MySQL. 16 | */ 17 | class SlickJdbcUrlBuilderForMySQL extends SlickJdbcUrlBuilder with BasicDatabaseConfig { 18 | 19 | // --[ Properties ]----------------------------------------------------------- 20 | val FMT_URL_DEFALT = """jdbc:mysql://%s/%s""" 21 | val FMT_URL_LOADBALANCE = """jdbc:mysql:loadbalance://%s/%s""" 22 | 23 | // --[ Methods ]-------------------------------------------------------------- 24 | /** 25 | * Generate a url for JDBC connection resouce. 26 | */ 27 | def buildUrl(implicit dsn: DataSourceName): Try[String] = 28 | for { 29 | hosts <- getHosts 30 | database <- getDatabaseName 31 | } yield hosts.size match { 32 | case 1 => FMT_URL_DEFALT.format(hosts.head, database) 33 | case _ => FMT_URL_LOADBALANCE.format(hosts.mkString(","), database) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/util/PolyLeftJoinSyntax.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.util 10 | 11 | import shapeless.{ HList, Poly2 } 12 | import shapeless.ops.hlist.LeftFolder 13 | 14 | /** 15 | * Polymorphic left join operation 16 | */ 17 | case class PolyLeftJoinSyntax[R, P <: Poly2](underlying: R, poly2: P) { 18 | 19 | /** 20 | * Join operation 21 | */ 22 | def apply[L <: HList](haystack: L) 23 | (implicit folder: LeftFolder[L, R, poly2.type]): folder.Out = 24 | haystack.foldLeft(underlying)(poly2) 25 | } 26 | 27 | /** 28 | * Companion object 29 | */ 30 | object PolyLeftJoinSyntax { 31 | 32 | trait Rule[R] extends Poly2 { 33 | 34 | /** 35 | * Implicit convert: T => Seq[T] 36 | */ 37 | implicit def caseAnyRef[T](implicit st: Case[R, Seq[T]]) = 38 | at[R, T]((root, haystack) => this(root, Seq(haystack))) 39 | 40 | /** 41 | * Implicit convert: Option[T] => Seq[T] 42 | */ 43 | implicit def caseOpt[T](implicit st: Case[R, Seq[T]]) = 44 | at[R, Option[T]]((root, haystack) => this(root, haystack.toSeq)) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /framework/ixias-core/src/test/scala/ixias/persistence/backend/BasicDatabaseContainerTest.scala: -------------------------------------------------------------------------------- 1 | package ixias.persistence.backend 2 | 3 | import ixias.persistence.model.DataSourceName 4 | import org.specs2.mutable._ 5 | 6 | import scala.concurrent.ExecutionContext.Implicits.global 7 | import scala.concurrent.duration.Duration 8 | import scala.concurrent.{Await, Future} 9 | 10 | class BasicDatabaseContainerTest extends Specification { 11 | 12 | case class Database() { 13 | var count = 0 14 | def incrementAndGet(): Database = { 15 | count += 1 16 | this 17 | } 18 | } 19 | 20 | val container = new BasicDatabaseContainer[Database]{} 21 | 22 | "DatabaseContainer" should { 23 | "be thread safe" in { 24 | val db = Database() 25 | implicit val datasource = DataSourceName("", "", "") 26 | val result = (0 to 1000) map { _ => 27 | Future { 28 | Thread.sleep(100) 29 | container.getOrElseUpdate { 30 | Thread.sleep(100) 31 | Future.successful(db.incrementAndGet()) 32 | } 33 | }.flatten 34 | } 35 | Await.ready(Future.sequence(result), Duration.Inf) 36 | db.count must_=== 1 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /framework/ixias-play-auth/src/main/scala/ixias/play/api/auth/token/TokenViaHttpHeader.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.auth.token 10 | 11 | import play.api.mvc.{ RequestHeader, Result } 12 | 13 | case class TokenViaHttpHeader(val name: String) extends Token { 14 | import Token._ 15 | 16 | // The configuration 17 | def headerName = config.get[String](s"session.${name}.headerName") 18 | 19 | /** 20 | * Put a specified security token to HTTP-Headers. 21 | */ 22 | def put(token: AuthenticityToken)(result: Result)(implicit request: RequestHeader): Result = { 23 | val signed = Token.signWithHMAC(token) 24 | result.withHeaders(headerName -> SignedToken.unwrap(signed)) 25 | } 26 | 27 | /** 28 | * Discard a security token. 29 | */ 30 | def discard(result: Result)(implicit request: RequestHeader): Result = result 31 | 32 | /** 33 | * Extract a security token from HTTP-Headers. 34 | */ 35 | def extract(implicit request: RequestHeader): Option[AuthenticityToken] = 36 | for { 37 | signed <- request.headers.get(headerName).map(SignedToken(_)) 38 | token <- Token.verifyHMAC(signed) 39 | } yield token 40 | } 41 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/model/Table.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.model 10 | 11 | import ixias.model._ 12 | 13 | /** 14 | * The model of AmazonQLDB table. 15 | */ 16 | trait Table[K <: Document.Id[_], M <: EntityModel[K]] { 17 | 18 | //-- [ Properties ] ---------------------------------------------------------- 19 | /** Data storage location information */ 20 | val dsn: DataSourceName 21 | 22 | /** Table queries */ 23 | val query: Query 24 | 25 | //-- [ Table Query ] --------------------------------------------------------- 26 | type Query <: TableQuery 27 | type BasicQuery = TableQuery 28 | 29 | type TableQuery = ixias.aws.qldb.model.TableQuery[K, M] 30 | type DataSourceName = ixias.persistence.model.DataSourceName 31 | val DataSourceName = ixias.persistence.model.DataSourceName 32 | 33 | //-- [ Utility Methods ] ----------------------------------------------------- 34 | /** 35 | * Overwrite function if necessary. 36 | * As you add and change features in your app, 37 | * you need to modify your entity classes to reflect these adjust. 38 | */ 39 | def migrate[A](data: A): A = data 40 | } 41 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/mvc/JsonHelper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.mvc 10 | 11 | import play.api.mvc._ 12 | import play.api.mvc.Results.BadRequest 13 | import play.api.libs.json.{ Reads, JsSuccess, JsError } 14 | 15 | // Helper for JSON 16 | //~~~~~~~~~~~~~~~~~~ 17 | trait JsonHelper { 18 | 19 | /** 20 | * To bind request data to a `T` component. 21 | */ 22 | def bindFromRequest[T] 23 | (implicit req: Request[AnyContent], reads: Reads[T]): Either[Result, T] 24 | } 25 | 26 | /** 27 | * Default helper 28 | */ 29 | object JsonHelper extends JsonHelper with ixias.util.Logging { 30 | 31 | /** 32 | * To bind request data to a `T` component. 33 | */ 34 | def bindFromRequest[T] 35 | (implicit req: Request[AnyContent], reads: Reads[T]): Either[Result, T] = 36 | req.body.asJson match { 37 | case None => Left(BadRequest) 38 | case Some(json) => json.validate[T] match { 39 | case JsSuccess(v, _) => Right(v) 40 | case JsError(errs) => { 41 | logger.error(JsError.toJson(errs).toString()) 42 | Left(BadRequest(JsError.toJson(errs))) 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/mvc/FormHelper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.mvc 10 | 11 | import play.api.data.{ Form, Mapping, FormBinding, DefaultFormBinding } 12 | import play.api.mvc.{ Request, Result } 13 | import play.api.mvc.Results.BadRequest 14 | import play.api.i18n.MessagesProvider 15 | 16 | // Helper for HTTP-POST data 17 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 | trait FormHelper { 19 | 20 | /** 21 | * To bind request data to a `T` component. 22 | */ 23 | def bindFromRequest[T](mapping: Mapping[T])(implicit 24 | req: Request[_], 25 | provider: MessagesProvider 26 | ): Either[Result, T] 27 | } 28 | 29 | /** 30 | * Default helper 31 | */ 32 | object FormHelper extends FormHelper { 33 | 34 | implicit val formBinding: FormBinding = 35 | new DefaultFormBinding(Form.FromJsonMaxChars) 36 | 37 | /** 38 | * To bind request data to a `T` component. 39 | */ 40 | def bindFromRequest[T](mapping: Mapping[T])(implicit 41 | req: Request[_], 42 | provider: MessagesProvider, 43 | ): Either[Result, T] = 44 | Form(mapping).bindFromRequest().fold( 45 | f => Left(BadRequest(f.errorsAsJson)), 46 | v => Right(v) 47 | ) 48 | } 49 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/model/Cursor.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.model 10 | 11 | /** 12 | * A database cursor is a control structure that enables 13 | * traversal over the records in a database. 14 | */ 15 | case class Cursor( 16 | val offset: Long = 0L, // Select all elements except the first ones. 17 | val limit: Option[Long] = Some(10L) // Select the first elements. 18 | ) extends CursorLike 19 | 20 | /** 21 | * Companion object 22 | */ 23 | object Cursor { 24 | 25 | /** Create a new cursor object with a limit parameter */ 26 | def apply(n: Long) = new Cursor(limit = Some(n)) 27 | def apply(n: Option[Long]) = new Cursor(limit = n) 28 | } 29 | 30 | /** 31 | * The cursor's future implementation. 32 | */ 33 | trait CursorLike { self: Cursor => 34 | 35 | /** Updates position by specified value. */ 36 | def set(pos: Long): Cursor = { 37 | this.copy(offset = pos) 38 | } 39 | 40 | /** Sets position of the next element. */ 41 | def next: Cursor = { 42 | limit.fold(this)(v => this.copy(offset = offset + v)) 43 | } 44 | 45 | /** Rewind the position. */ 46 | def rewind: Cursor = { 47 | this.copy(offset = 0) 48 | } 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /framework/ixias-play-auth/src/main/scala/ixias/play/api/auth/mvc/Authenticated.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.auth.mvc 10 | 11 | import play.api.mvc._ 12 | import scala.concurrent.{ Future, ExecutionContext } 13 | 14 | /** 15 | * Provides the custom action for authentication. 16 | */ 17 | trait AuthenticatedActionBuilder extends ActionBuilder[Request, AnyContent] 18 | object AuthenticatedActionBuilder { 19 | def apply(auth: AuthProfile[_, _, _], parser: BodyParser[AnyContent]) 20 | (implicit ec: ExecutionContext): AuthenticatedActionBuilder = 21 | new AuthenticatedActionBuilderImpl(auth, parser) 22 | } 23 | 24 | // Implementation for authentication 25 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 26 | class AuthenticatedActionBuilderImpl( 27 | val auth: AuthProfile[_, _, _], 28 | val parser: BodyParser[AnyContent] 29 | )(implicit val executionContext: ExecutionContext) extends AuthenticatedActionBuilder { 30 | 31 | /** Invoke the block. */ 32 | def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = { 33 | auth.authenticate(request) flatMap { 34 | case Left(failed) => Future.successful(failed) 35 | case Right((data, updater)) => block { 36 | request.addAttr(auth.RequestAttrKey.Auth, data) 37 | } map updater 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /framework/ixias-play-auth/src/main/scala/ixias/play/api/auth/mvc/AuthenticatedOrNot.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.auth.mvc 10 | 11 | import play.api.mvc._ 12 | import scala.concurrent.{ Future, ExecutionContext } 13 | 14 | /** 15 | * Provides the custom action for authentication. 16 | */ 17 | trait AuthenticatedOrNotActionBuilder extends ActionBuilder[Request, AnyContent] 18 | object AuthenticatedOrNotActionBuilder { 19 | def apply(auth: AuthProfile[_, _, _], parser: BodyParser[AnyContent]) 20 | (implicit ec: ExecutionContext): AuthenticatedOrNotActionBuilder = 21 | new AuthenticatedOrNotActionBuilderImpl(auth, parser) 22 | } 23 | 24 | // Implementation for authentication 25 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 26 | class AuthenticatedOrNotActionBuilderImpl( 27 | val auth: AuthProfile[_, _, _], 28 | val parser: BodyParser[AnyContent] 29 | )(implicit val executionContext: ExecutionContext) extends AuthenticatedOrNotActionBuilder { 30 | 31 | /** Invoke the block. */ 32 | def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = { 33 | auth.restore(request) flatMap { 34 | case (None, updater) => block(request).map(updater) 35 | case (Some(data), updater) => block { 36 | request.addAttr(auth.RequestAttrKey.Auth, data) 37 | } map updater 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /framework/ixias-play-auth/src/main/scala/ixias/play/api/auth/mvc/Authorized.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.auth.mvc 10 | 11 | import play.api.mvc._ 12 | import scala.concurrent.{ Future, ExecutionContext } 13 | 14 | /** 15 | * Provides the custom action for authorization. 16 | */ 17 | trait AuthorizedActionBuilder extends ActionBuilder[Request, AnyContent] 18 | object AuthorizedActionBuilder { 19 | def apply[T](auth: AuthProfile[_, _, T], authority: Option[T], parser: BodyParser[AnyContent]) 20 | (implicit ec: ExecutionContext): AuthorizedActionBuilder = 21 | new AuthorizedActionBuilderImpl(auth, authority, parser) 22 | } 23 | 24 | // Implementation for authorization 25 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 26 | class AuthorizedActionBuilderImpl[T]( 27 | val auth: AuthProfile[_, _, T], 28 | val authority: Option[T], 29 | val parser: BodyParser[AnyContent] 30 | )(implicit val executionContext: ExecutionContext) extends AuthorizedActionBuilder { 31 | 32 | /** Invoke the block. */ 33 | def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = { 34 | auth.authorize(authority)(request) flatMap { 35 | case Left(failed) => Future.successful(failed) 36 | case Right((data, updater)) => block { 37 | request.addAttr(auth.RequestAttrKey.Auth, data) 38 | } map updater 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/lifted/SlickDBIOActionOps.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.lifted 10 | 11 | import ixias.model._ 12 | import slick.dbio.{ DBIOAction, NoStream, Effect } 13 | import scala.concurrent.ExecutionContext 14 | import scala.language.implicitConversions 15 | import scala.reflect.ClassTag 16 | 17 | final case class SlickDBIOActionTransformer[K <: @@[_, _], M <: EntityModel[K], E <: Effect] 18 | (val self: DBIOAction[_, NoStream, E]) extends AnyVal 19 | { 20 | // Seq[M] => Seq[Entity.EmbeddedId[K, M]] 21 | def toEntity(implicit ctag: ClassTag[Seq[M]], ex: ExecutionContext): 22 | DBIOAction[Seq[Entity.EmbeddedId[K, M]], NoStream, E] = self collect { 23 | case itr if ctag.runtimeClass.isInstance(itr) => 24 | itr.asInstanceOf[Seq[M]].map(Entity.EmbeddedId[K, M](_)) 25 | } 26 | 27 | // Seq[M] => Seq[R2] 28 | def mapEntity[R2](fn: Entity.EmbeddedId[K, M] => R2)(implicit ctag: ClassTag[Seq[M]], ex: ExecutionContext): 29 | DBIOAction[Seq[R2], NoStream, E] = self collect { 30 | case itr if ctag.runtimeClass.isInstance(itr) => 31 | itr.asInstanceOf[Seq[M]].map(m => fn(Entity.EmbeddedId[K, M](m))) 32 | } 33 | } 34 | 35 | trait SlickDBIOActionOps[K <: @@[_, _], M <: EntityModel[K]] { 36 | implicit def toDBIOActionTransformer[E <: Effect](a: DBIOAction[Seq[M], NoStream, E]) = 37 | SlickDBIOActionTransformer[K, M, E](a) 38 | } 39 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/security/Token.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.security 10 | 11 | /** 12 | * The component to provides common methods. 13 | */ 14 | trait Token { 15 | 16 | protected val generator: TokenGenerator 17 | 18 | /** 19 | * Generate a new token as string 20 | */ 21 | def next(length: Int): String = generator.next(length) 22 | 23 | /** 24 | * Do not change this unless you understand the security issues behind timing attacks. 25 | * This method intentionally runs in constant time if the two strings have the same length. 26 | */ 27 | final def safeEquals(a: String, b: String) = { 28 | if (a.length != b.length) { 29 | false 30 | } else { 31 | var equal = 0 32 | for (i <- Array.range(0, a.length)) { 33 | equal |= a(i) ^ b(i) 34 | } 35 | equal == 0 36 | } 37 | } 38 | } 39 | 40 | /** 41 | * The component to manage token as string 42 | */ 43 | object RandomPINCode extends Token { 44 | 45 | /** The token provider */ 46 | protected val generator = TokenGenerator( 47 | table = "1234567890" 48 | ) 49 | } 50 | 51 | /** 52 | * The component to manage pin as numeric number 53 | */ 54 | object RandomStringToken extends Token { 55 | 56 | /** The token provider */ 57 | protected val generator = TokenGenerator( 58 | table = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" 59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/databind/EnumStatusSerializerModule.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.databind 10 | 11 | import com.fasterxml.jackson.databind._ 12 | import com.fasterxml.jackson.databind.ser.Serializers 13 | import com.fasterxml.jackson.core.JsonGenerator 14 | import com.fasterxml.jackson.module.scala.JacksonModule 15 | import ixias.util.EnumStatus 16 | 17 | // Serialize Objects of `EnumStatus` 18 | // into JSON, using provided JsonGenerator. 19 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20 | object EnumStatusSerializer extends JsonSerializer[EnumStatus] { 21 | def serialize(value: EnumStatus, jgen: JsonGenerator, provider: SerializerProvider): Unit = 22 | jgen.writeNumber(value.code) 23 | } 24 | 25 | // Resolver to serve serializer 26 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 27 | object EnumStatusSerializerResolver extends Serializers.Base { 28 | private val SYMBOL = classOf[EnumStatus] 29 | override def findSerializer( 30 | config: SerializationConfig, 31 | javaType: JavaType, 32 | beanDesc: BeanDescription 33 | ): JsonSerializer[_] = 34 | SYMBOL isAssignableFrom javaType.getRawClass match { 35 | case true => EnumStatusSerializer 36 | case false => null 37 | } 38 | } 39 | 40 | // Jackson Module Definition 41 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 42 | trait EnumStatusSerializerModule extends JacksonModule { 43 | this += { _ addSerializers EnumStatusSerializerResolver } 44 | } 45 | -------------------------------------------------------------------------------- /framework/ixias-aws-sns/src/main/scala/ixias/aws/sns/backend/AmazonSNSBackend.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.sns.backend 10 | 11 | import scala.concurrent.Future 12 | import scala.util.{ Success, Failure } 13 | import ixias.util.Logger 14 | import ixias.persistence.dbio.Execution 15 | import com.amazonaws.auth.AWSStaticCredentialsProvider 16 | import com.amazonaws.services.sns.{ AmazonSNS, AmazonSNSClientBuilder } 17 | 18 | /** 19 | * The backend to get a client for AmazonSNS. 20 | */ 21 | object AmazonSNSBackend extends AmazonSNSConfig { 22 | 23 | /** The logger for profile */ 24 | protected lazy val logger = Logger.apply 25 | 26 | /** The Execution Context */ 27 | protected implicit val ctx = Execution.Implicits.trampoline 28 | 29 | /** Get a Client to manage Amazon SNS. */ 30 | def getClient(implicit dsn: DataSourceName): Future[AmazonSNS] = { 31 | logger.debug("Get a database dsn=%s hash=%s".format(dsn.toString, dsn.hashCode)) 32 | Future.fromTry( 33 | for { 34 | credentials <- getAWSCredentials 35 | region <- getAWSRegion 36 | } yield AmazonSNSClientBuilder.standard 37 | .withCredentials(new AWSStaticCredentialsProvider(credentials)) 38 | .withRegion(region) 39 | .build 40 | ) andThen { 41 | case Success(_) => logger.info("Generated a new client. dsn=%s".format(dsn.toString)) 42 | case Failure(_) => logger.info("Failed to build a client. dsn=%s".format(dsn.toString)) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /framework/ixias-play-auth/src/main/scala/ixias/play/api/auth/container/Container.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.auth.container 10 | 11 | import java.time.Duration 12 | import scala.concurrent.Future 13 | 14 | import ixias.model._ 15 | import ixias.play.api.auth.token.Token 16 | import play.api.mvc.RequestHeader 17 | 18 | /** 19 | * The container for session's tokens. 20 | */ 21 | trait Container[K <: @@[_, _]] { 22 | import Token._ 23 | 24 | /** The type of entity id */ 25 | type Id = K 26 | 27 | /** The execution context */ 28 | implicit val executionContext: scala.concurrent.ExecutionContext 29 | 30 | /** 31 | * It is the first callback function executed 32 | * when the session is started automatically or manually. 33 | */ 34 | def open(uid: Id, expiry: Option[Duration]) 35 | (implicit request: RequestHeader): Future[AuthenticityToken] 36 | 37 | /** 38 | * Sets the timeout setting. 39 | */ 40 | def setTimeout(token: AuthenticityToken, expiry: Option[Duration]) 41 | (implicit request: RequestHeader): Future[Unit] 42 | 43 | /** 44 | * The read callback must always return 45 | * a user identity or none if there is no data to read. 46 | */ 47 | def read(token: AuthenticityToken) 48 | (implicit request: RequestHeader): Future[Option[Id]] 49 | 50 | /** 51 | * This callback is executed when a session is destroyed. 52 | */ 53 | def destroy(token: AuthenticityToken) 54 | (implicit request: RequestHeader): Future[Unit] 55 | } 56 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/Repository.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence 10 | 11 | import ixias.model.{ @@, EntityModel } 12 | import ixias.persistence.dbio.{ Execution, EntityIOAction } 13 | import ixias.persistence.lifted.{ Aliases, ExtensionMethods } 14 | 15 | import ixias.util.Logger 16 | import org.slf4j.LoggerFactory 17 | 18 | /** 19 | * The basic functionality that has to be implemented by all profiles. 20 | */ 21 | trait Profile { 22 | 23 | /** The type of database objects. */ 24 | type Database <: AnyRef 25 | 26 | /** The back-end type required by this profile */ 27 | type Backend <: ixias.persistence.backend.BasicBackend[Database] 28 | 29 | /** The back-end implementation for this profile */ 30 | protected val backend: Backend 31 | 32 | /** The logger for profile */ 33 | protected lazy val logger = 34 | new Logger(LoggerFactory.getLogger(this.getClass.getName)) 35 | 36 | /** The Execution Context */ 37 | protected implicit val ctx = Execution.Implicits.trampoline 38 | 39 | /** 40 | * The API for using the utility methods with a single import statement. 41 | * This provides the repository's implicits, the Database connections, 42 | * and commonly types and objects. 43 | */ 44 | trait API extends Aliases with ExtensionMethods 45 | val api: API 46 | } 47 | 48 | /** 49 | * The basic repository with IOAction 50 | */ 51 | trait Repository[K <: @@[_, _], M <: EntityModel[K]] 52 | extends Profile with EntityIOAction[K, M] 53 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/dbio/DBIOAction.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.dbio 10 | 11 | import scala.concurrent.{ Future, ExecutionContext } 12 | import software.amazon.qldb.{ QldbSession, TransactionExecutor } 13 | import ixias.aws.qldb.model.{ SqlStatement, ConvOps } 14 | 15 | /** 16 | * Executor for database IO/Action. 17 | */ 18 | case class DBIOAction(session: QldbSession) extends ConvOps { 19 | 20 | /** 21 | * Execute query 22 | */ 23 | def execute(stmt: SqlStatement): Future[stmt.Result] = 24 | Future.fromTry(stmt.execute(session)) 25 | 26 | /** 27 | * Transaction block 28 | * Since transaction commit is called when the Executor ends, 29 | * it waits for the end of block processing. 30 | */ 31 | def transaction[A](block: DBIOActionWithTxt => Future[A]): Future[A] = 32 | session.execute(tx => { 33 | import scala.concurrent.Await 34 | import scala.concurrent.duration.Duration 35 | import java.util.concurrent.ForkJoinPool 36 | implicit val ex = ExecutionContext.fromExecutor(new ForkJoinPool()) 37 | Await.ready( 38 | Future.unit.flatMap(_ => block(DBIOActionWithTxt(tx))), 39 | Duration.Inf 40 | ) 41 | }) 42 | } 43 | 44 | /** 45 | * Executor for database IO/Action with transaction. 46 | */ 47 | case class DBIOActionWithTxt(tx: TransactionExecutor) extends ConvOps { 48 | 49 | /** 50 | * Execute query with transaction 51 | */ 52 | def execute(stmt: SqlStatement): Future[stmt.Result] = 53 | Future.fromTry(stmt.execute(tx)) 54 | } 55 | 56 | -------------------------------------------------------------------------------- /framework/ixias-mail/src/main/scala/ixias/EmailClient.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.mail 10 | 11 | import scala.concurrent.{ Future, ExecutionContext } 12 | import com.google.inject.AbstractModule 13 | import com.google.inject.name.Names 14 | 15 | import ixias.util.Logger 16 | import org.slf4j.LoggerFactory 17 | 18 | // Module declaration 19 | //~~~~~~~~~~~~~~~~~~~~~ 20 | class MailerModule extends AbstractModule { 21 | override def configure(): Unit = { 22 | bind(classOf[EmailClient]) 23 | .annotatedWith(Names.named("smtp")) 24 | .to(classOf[EmailClientViaSMTP]) 25 | bind(classOf[EmailClient]) 26 | .annotatedWith(Names.named("twillio")) 27 | .to(classOf[EmailClientViaTwillio]) 28 | } 29 | } 30 | 31 | // Email Sender 32 | //~~~~~~~~~~~~~~ 33 | trait EmailClient { 34 | 35 | /** The logger */ 36 | protected lazy val logger = 37 | new Logger(LoggerFactory.getLogger(this.getClass.getName)) 38 | 39 | // --[ Methods ]-------------------------------------------------------------- 40 | /** 41 | * Send an email with the provided data. 42 | */ 43 | def send(to: UserEmail, tpl: EmailTemplate[_]) 44 | (implicit ctx: ExecutionContext): Future[String] = 45 | tpl.from match { 46 | case Some(from) => send(to, from, tpl) 47 | case None => Future.failed(new NoSuchElementException("The from adrress is empty.")) 48 | } 49 | 50 | /** 51 | * Send an email with the provided data. 52 | */ 53 | def send(to: UserEmail, from: UserEmail, tpl: EmailTemplate[_]) 54 | (implicit ctx: ExecutionContext): Future[String] 55 | } 56 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/AmazonQLDB.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb 10 | 11 | import ixias.model._ 12 | import ixias.persistence.{ Profile, Repository } 13 | import ixias.aws.qldb.backend.{ AmazonQLDBBackend, AmazonQLDBActionProvider } 14 | 15 | trait AmazonQLDBProfile extends Profile 16 | with AmazonQLDBActionProvider { 17 | 18 | // --[ Typedefs ]------------------------------------------------------------- 19 | /** The type of database objects. */ 20 | type Database = AmazonQLDBBackend.type#Database 21 | 22 | /** The back-end type required by this profile */ 23 | type Backend = AmazonQLDBBackend.type 24 | 25 | // --[ Alias ]---------------------------------------------------------------- 26 | val DataSourceName = ixias.persistence.model.DataSourceName 27 | 28 | // --[ Properties ]----------------------------------------------------------- 29 | /** The back-end implementation for this profile */ 30 | protected lazy val backend = AmazonQLDBBackend 31 | 32 | /** 33 | * The API for using the utility methods with a single import statement. 34 | * This provides the repository's implicits, the Database connections, 35 | * and commonly types and objects. 36 | */ 37 | trait API extends super.API 38 | val api: API = new API {} 39 | } 40 | 41 | /** 42 | * The repository for persistence with using the Slick library. 43 | */ 44 | trait AmazonQLDBRepository[K <: @@[_, _], M <: EntityModel[K]] 45 | extends Repository[K, M] with AmazonQLDBProfile { 46 | trait API extends super.API 47 | override val api: API = new API {} 48 | } 49 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/backend/SlickJdbcUrlBuilder.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.backend 10 | 11 | import scala.util.{ Try, Success, Failure } 12 | import ixias.persistence.model.DataSourceName 13 | 14 | /** 15 | * Provide a feature to build JDBC-Url. 16 | */ 17 | trait SlickJdbcUrlBuilder { 18 | 19 | /** 20 | * Generate a url for JDBC connection resouce. 21 | */ 22 | def buildUrl(implicit dsn: DataSourceName): Try[String] 23 | } 24 | 25 | /** 26 | * The provider for SlickJdbcUrlBuilder 27 | */ 28 | object SlickJdbcUrlBuilderProvider { 29 | 30 | /** 31 | * Registered SlickJdbcUrlBuilders. 32 | */ 33 | private var stock: Map[String, SlickJdbcUrlBuilder] = Map( 34 | "com.mysql.jdbc.Driver" -> new SlickJdbcUrlBuilderForMySQL(), 35 | "com.mysql.cj.jdbc.Driver" -> new SlickJdbcUrlBuilderForMySQL(), 36 | "com.amazon.redshift.jdbc.Driver" -> new SlickJdbcUrlBuilderForRedshift() 37 | ) 38 | 39 | // --[ Methods ]-------------------------------------------------------------- 40 | /** 41 | * Retrive a UrlBuilder from registered stack. 42 | */ 43 | def resolve(driver: String): Try[SlickJdbcUrlBuilder] = 44 | stock.get(driver) match { 45 | case Some(v) => Success(v) 46 | case None => Failure(new IllegalArgumentException( 47 | "Could not resolve the JDBC vendor format. %s".format(driver) 48 | )) 49 | } 50 | 51 | /** 52 | * Register a UrlBuilder to stack. 53 | */ 54 | def register(driverName: String, builder: SlickJdbcUrlBuilder): Unit = 55 | this.stock = this.stock + (driverName -> builder) 56 | } 57 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/backend/ShadeConfig.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.backend 10 | 11 | import scala.util.Try 12 | import java.util.concurrent.TimeUnit 13 | import scala.concurrent.duration.FiniteDuration 14 | import ixias.persistence.model.DataSourceName 15 | 16 | trait ShadeConfig extends BasicDatabaseConfig { 17 | 18 | // --[ Properties ]----------------------------------------------------------- 19 | /** The keys of configuration */ 20 | protected val CF_KEY_PREFIX = "keys_prefix" 21 | protected val CF_OP_TIMEOUT = "operation_timeout" 22 | 23 | // --[ Methods ]-------------------------------------------------------------- 24 | /** 25 | * Get the list of server addresses, separated by space. 26 | */ 27 | protected def getAddresses(implicit dsn: DataSourceName): Try[String] = 28 | getHosts.map(_.mkString(",")) 29 | 30 | /** 31 | * Get the prefix to be added to used keys when storing/retrieving values 32 | * useful for having the same Memcached instances used by several 33 | * applications to prevent them from stepping over each other. 34 | */ 35 | protected def getKeysPrefix(implicit dsn: DataSourceName): String = 36 | readValue(_.get[Option[String]](CF_KEY_PREFIX)).getOrElse(dsn.database + "#") 37 | 38 | /** 39 | * Get the operation timeout; When the limit is reached, 40 | * the Future responses finish with Failure(TimeoutException) 41 | */ 42 | protected def getHostSpecIdleTimeout(implicit dsn: DataSourceName): FiniteDuration = 43 | readValue(_.get[Option[FiniteDuration]](CF_OP_TIMEOUT)) 44 | .getOrElse(FiniteDuration(30000, TimeUnit.MILLISECONDS)) 45 | } 46 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/backend/AmazonQLDBAction.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.backend 10 | 11 | import scala.concurrent.Future 12 | import ixias.persistence.action.BasicAction 13 | 14 | import ixias.aws.qldb.model.Table 15 | import ixias.aws.qldb.dbio.DBIOAction 16 | import ixias.aws.qldb.AmazonQLDBProfile 17 | 18 | trait AmazonQLDBActionProvider { self: AmazonQLDBProfile => 19 | 20 | /** 21 | * The Request of Invocation. 22 | */ 23 | sealed case class DBActionRequest[T <: Table[_, _]](table: T) 24 | 25 | /** 26 | * The base action to execute query. 27 | */ 28 | sealed case class DBAction[T <: Table[_, _]]() 29 | extends BasicAction[DBActionRequest[T], (DBIOAction, T#Query)] { 30 | type Request = DBActionRequest[T] 31 | type BlockFunction[A] = ((DBIOAction, T#Query)) => Future[A] 32 | 33 | /** Invoke the block. */ 34 | def invokeBlock[A](req: Request, block: BlockFunction[A]): Future[A] = 35 | (for { 36 | session <- backend.getDatabase(req.table.dsn) 37 | value <- block(DBIOAction(session) -> req.table.query) 38 | } yield value) andThen { 39 | case scala.util.Failure(ex) => logger.error( 40 | "The database action failed. dsn=%s".format(req.table.dsn.toString), ex) 41 | } 42 | } 43 | 44 | /** 45 | * Execute database action. 46 | */ 47 | object RunDBAction { 48 | def apply[A, B, T <: Table[_, _]] 49 | (table: T) 50 | (block: ((DBIOAction, T#Query)) => Future[A]) 51 | (implicit conv: A => B): Future[B] = 52 | DBAction[T].invokeBlock(DBActionRequest(table), block) 53 | .map(conv) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/model/DataSourceName.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.model 10 | 11 | /** 12 | * The DSN(Data-Source-Name) structure. 13 | */ 14 | case class DataSourceName( 15 | val path: String, 16 | val hostspec: String, 17 | val database: String 18 | ) { 19 | /** Compares two DSN structurally */ 20 | override final def equals(other: Any): Boolean = other match { 21 | case that: DataSourceName => { 22 | (that _equal this) && 23 | (this.path == that.path) && 24 | (this.hostspec == that.hostspec) && 25 | (this.database == that.database) 26 | } 27 | case _ => false 28 | } 29 | private def _equal(other: Any) = other.isInstanceOf[DataSourceName] 30 | 31 | /** Returns the hash code for this `DataSourceName`. */ 32 | override final def hashCode: Int = 33 | 31 ^ 3 * path.## + 31 ^ 2 * hostspec.## + 31 ^ 1 * database.## 34 | 35 | /** The String representation of the `DataSourceName` companion object. */ 36 | override final def toString: String = "%s://%s/%s".format(path, hostspec, database) 37 | } 38 | 39 | /** 40 | * Conpanion object. 41 | */ 42 | object DataSourceName { 43 | 44 | /** The synatx format for DSN */ 45 | val SYNTAX_DATA_SOURCE_NAME = """^([.\w]+)://(\w+?)/(\w+)$""".r 46 | 47 | val RESERVED_NAME_MASTER = "master" 48 | val RESERVED_NAME_SLAVE = "slave" 49 | 50 | /** Build a `DataSourceName` object. */ 51 | def apply(dsn: String): DataSourceName = dsn match { 52 | case SYNTAX_DATA_SOURCE_NAME(p1, p2, p3) => DataSourceName(p1, p2, p3) 53 | case _ => throw new Exception(s"""Dose not match the DSN format. ($dsn)""") 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/mvc/BaseExtensionMethods.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.mvc 10 | 11 | import play.api.mvc._ 12 | import cats.data.EitherT 13 | import cats.instances.future._ 14 | import scala.concurrent.Future 15 | import scala.language.implicitConversions 16 | 17 | trait BaseExtensionMethods { self: BaseControllerHelpers => 18 | val Cursor = ixias.persistence.model.Cursor 19 | val AttrHelper = ixias.play.api.mvc.RequestHeaderAttrHelper 20 | val FormHelper: ixias.play.api.mvc.FormHelper = ixias.play.api.mvc.FormHelper 21 | val JsonHelper: ixias.play.api.mvc.JsonHelper = ixias.play.api.mvc.JsonHelper 22 | 23 | /** The ExecutionContext with using on Playframework. */ 24 | implicit lazy val executionContext = defaultExecutionContext 25 | 26 | // --[ Methods ] ------------------------------------------------------------- 27 | // Either[Result, Result] -> Result 28 | implicit def convEitherToResult(v: Either[Result, Result]): Result = 29 | v match { case Right(r) => r case Left(l) => l } 30 | 31 | // Future[Either[Result, Result]] -> Future[Result] 32 | implicit def convEitherToResult(f: Future[Either[Result, Result]]): Future[Result] = 33 | f.map(convEitherToResult(_)) 34 | 35 | // EitherT[Future, Result, Result] -> Future[Result] 36 | implicit def convEitherToResult(t: EitherT[Future, Result, Result]): Future[Result] = 37 | t.valueOr(v => v) 38 | 39 | // --[ Methods ] ------------------------------------------------------------- 40 | def DeviceDetection: ActionBuilder[Request, AnyContent] = DeviceDetectionBuilder(parse.default) 41 | val DeviceDetectionAttrKey = ixias.play.api.mvc.DeviceDetectionAttrKey 42 | } 43 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/security/TokenSigner.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.security 10 | 11 | import scala.util.Try 12 | import com.typesafe.config.ConfigFactory 13 | 14 | import org.keyczar.Signer 15 | import org.keyczar.HmacKey 16 | import org.keyczar.interfaces.KeyczarReader 17 | import org.apache.commons.codec.binary.{Hex, StringUtils} 18 | import org.apache.commons.codec.digest.DigestUtils 19 | 20 | /** 21 | * TokenVerifiers verify session token signatures generated. 22 | */ 23 | case class TokenSigner(reader: KeyczarReader) { 24 | 25 | lazy val signer = new Signer(reader) 26 | 27 | /** 28 | * Signs the input and produces a signature. 29 | */ 30 | def sign(token: String): String = { 31 | val signature = signer.sign(StringUtils.getBytesUsAscii(token)) 32 | new String(Hex.encodeHex(signature)) + token 33 | } 34 | 35 | /** 36 | * Verify the session token signature on the given data 37 | */ 38 | def verify(signedToken: String): Try[String] = 39 | Try { 40 | val (signature, token) = signedToken.splitAt(signer.digestSize * 2) 41 | signer.verify( 42 | StringUtils.getBytesUsAscii(token), 43 | Hex.decodeHex(signature.toCharArray) 44 | ) match { 45 | case true => token 46 | case false => throw new java.security.SignatureException 47 | } 48 | } 49 | } 50 | 51 | // Companion object 52 | //~~~~~~~~~~~~~~~~~~ 53 | object TokenSigner { 54 | 55 | /** Creates a TokenSigner. */ 56 | def apply() = { 57 | val config = ConfigFactory.load() 58 | val secret = config.getString("session.token.secret") 59 | new TokenSigner(HmacKeyReader(new HmacKey(DigestUtils.sha256(secret)))) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/backend/ShadeBackend.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.backend 10 | 11 | import scala.util.{ Success, Failure } 12 | import scala.concurrent.Future 13 | import shade.memcached.{ Memcached, Configuration } 14 | import ixias.persistence.model.DataSourceName 15 | 16 | /** 17 | * The shade backend to handle the database and session. 18 | */ 19 | case class ShadeBackend() 20 | extends BasicBackend[Memcached] with ShadeConfig 21 | { 22 | /** Get a Database instance from connection pool. */ 23 | def getDatabase(implicit dsn: DataSourceName): Future[Database] = { 24 | logger.debug("Get a database dsn=%s hash=%s".format(dsn.toString, dsn.hashCode)) 25 | ShadeDatabaseContainer.getOrElseUpdate { 26 | (for { 27 | conf <- createConfiguration 28 | db = Memcached(conf) 29 | } yield db) andThen { 30 | case Success(_) => logger.info("Created a new data souce. dsn=%s".format(dsn.toString)) 31 | case Failure(_) => logger.info("Failed to create a data souce. dsn=%s".format(dsn.toString)) 32 | } 33 | } 34 | } 35 | 36 | /** Create a configuration for shade client to access memcached */ 37 | def createConfiguration(implicit dsn: DataSourceName): Future[Configuration] = 38 | Future.fromTry { 39 | for { 40 | addresses <- getAddresses 41 | } yield { 42 | shade.memcached.Configuration( 43 | addresses = addresses, 44 | keysPrefix = Some(getKeysPrefix), 45 | operationTimeout = getHostSpecIdleTimeout 46 | ) 47 | } 48 | } 49 | } 50 | 51 | /** Manage data sources associated with DSN. */ 52 | object ShadeDatabaseContainer extends BasicDatabaseContainer[Memcached] 53 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/util/LabelledGenericMerger.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.util 10 | 11 | import shapeless.{ HList, LabelledGeneric, Poly2 } 12 | import shapeless.ops.hlist._ 13 | import shapeless.ops.record._ 14 | 15 | /** 16 | * Merger: model to model with using `LabelledGeneric` 17 | */ 18 | trait LabelledGenericMerger[T, U] { 19 | 20 | object mf extends Poly2 { 21 | implicit def opt1[A] = at[A, A] ((v1, v2) => v2) 22 | implicit def opt2[A] = at[Option[A], Option[A]] ((v1, v2) => v2 orElse v1) 23 | } 24 | 25 | /** 26 | * Copies all enumerable own properties 27 | * from source object to a target object. 28 | */ 29 | def merge[RT <: HList, RU <: HList](data1: T, data2: U, hard: Boolean = false)(implicit 30 | lgenT: LabelledGeneric.Aux[T, RT], 31 | lgenU: LabelledGeneric.Aux[U, RU], 32 | merger: Merger.Aux[RT, RU, RT], 33 | mergeWith: MergeWith.Aux[RT, RU, mf.type, RT] 34 | ): T = lgenT.from(hard match { 35 | case true => merger(lgenT.to(data1), lgenU.to(data2)) 36 | case false => mergeWith(lgenT.to(data1), lgenU.to(data2)) 37 | }) 38 | 39 | /** 40 | * Copies all enumerable own properties 41 | * from source generic values to a target object. 42 | */ 43 | def mergeGen[RT <: HList, RU <: HList, RN <: HList](data: T, gen: RU, hard: Boolean = false)(implicit 44 | lgenT: LabelledGeneric.Aux[T, RT], 45 | intersection: Intersection.Aux[RU, RT, RN], 46 | merger: Merger.Aux[RT, RN, RT], 47 | mergeWith: MergeWith.Aux[RT, RN, mf.type, RT] 48 | ): T = lgenT.from(hard match { 49 | case true => merger(lgenT.to(data), gen.intersect[RT]) 50 | case false => mergeWith(lgenT.to(data), gen.intersect[RT]) 51 | }) 52 | } 53 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/databind/EnumStatusDeserializerModule.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.databind 10 | 11 | import com.fasterxml.jackson.databind._ 12 | import com.fasterxml.jackson.databind.deser.Deserializers 13 | import com.fasterxml.jackson.core.JsonParser 14 | import com.fasterxml.jackson.module.scala.JacksonModule 15 | import ixias.util.EnumStatus 16 | 17 | // Deserialize Objects of `EnumStatus` 18 | // from JSON, using provided JsonParser. 19 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20 | case class EnumStatusDeserializer( 21 | javaType: JavaType 22 | ) extends JsonDeserializer[EnumStatus] { 23 | override def deserialize(p: JsonParser, ctxt: DeserializationContext): EnumStatus = { 24 | val clazz = Class.forName(javaType.getRawClass.getName + "$") 25 | val module = clazz.getField("MODULE$").get(null) 26 | val method = clazz.getMethod("apply", classOf[Short]) 27 | val enum = method.invoke(module, p.getValueAsInt.toShort.asInstanceOf[AnyRef]) 28 | enum.asInstanceOf[EnumStatus] 29 | } 30 | } 31 | 32 | // Resolver to serve deserializer 33 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 34 | object EnumStatusDeserializerResolver extends Deserializers.Base { 35 | private val SYMBOL = classOf[EnumStatus] 36 | override def findBeanDeserializer( 37 | javaType: JavaType, 38 | config: DeserializationConfig, 39 | beanDesc: BeanDescription 40 | ): JsonDeserializer[_] = { 41 | if (SYMBOL isAssignableFrom javaType.getRawClass) 42 | EnumStatusDeserializer(javaType) 43 | else null 44 | } 45 | } 46 | 47 | // Jackson Module Definition 48 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 49 | trait EnumStatusDeserializerModule extends JacksonModule { 50 | this += { _ addDeserializers EnumStatusDeserializerResolver } 51 | } 52 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/security/KeyReader.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.security 10 | 11 | import org.keyczar._ 12 | import org.keyczar.enums.{ KeyPurpose, KeyStatus } 13 | import org.keyczar.interfaces.KeyczarReader 14 | 15 | /** 16 | * These will read key files from disk, 17 | */ 18 | class KeyReader( 19 | metadata: KeyMetadata, 20 | keys: Seq[KeyczarKey] 21 | ) extends KeyczarReader { 22 | 23 | /** Gets an input stream of a particular version of a key. */ 24 | def getKey: String = 25 | getKey(KeyMetadata.read(getMetadata) 26 | .getPrimaryVersion.getVersionNumber) 27 | 28 | /** Gets an input stream of the primary key. */ 29 | def getKey(version: Int): String = 30 | keys(version).toString 31 | 32 | /** Gets metadata for a set of keys */ 33 | def getMetadata: String = metadata.toString 34 | } 35 | 36 | 37 | /** 38 | * Keyczar KeyReader that reads from a HMAC private key file 39 | */ 40 | object HmacKeyReader { 41 | 42 | /** Creates a HmacKeyReader. */ 43 | def apply(key: HmacKey) = { 44 | val version = new KeyVersion(0, KeyStatus.PRIMARY, false) 45 | val metadata = new KeyMetadata("Imported from HMAC", KeyPurpose.SIGN_AND_VERIFY, DefaultKeyType.HMAC_SHA1) 46 | metadata.addVersion(version) 47 | new KeyReader(metadata = metadata, keys = IndexedSeq(key)) 48 | } 49 | } 50 | 51 | /** 52 | * Keyczar KeyReader that reads from a AES private key file 53 | */ 54 | object AesKeyReader { 55 | 56 | /** Creates a AesKeyReader. */ 57 | def apply(key: AesKey) = { 58 | val version = new KeyVersion(0, KeyStatus.PRIMARY, false) 59 | val metadata = new KeyMetadata("Imported from AES", KeyPurpose.DECRYPT_AND_ENCRYPT, DefaultKeyType.AES) 60 | metadata.addVersion(version) 61 | new KeyReader(metadata = metadata, keys = IndexedSeq(key)) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/mvc/Errors.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.mvc 10 | 11 | import play.api.mvc.Result 12 | import play.api.mvc.Results._ 13 | import play.api.http.Status._ 14 | import play.api.libs.json.Json 15 | import ixias.util.Logging 16 | import ixias.play.api.json.JsValueError 17 | 18 | /** 19 | * The component to represent error response. 20 | */ 21 | case class Error(status: Status, code: Int, message: Option[String] = None) extends Logging { 22 | 23 | /** Build a JSON response. */ 24 | def toResult: Result = { 25 | val message = this.message.getOrElse("An error occurred in the client.") 26 | logger.info("code:%d, message:%s".format(code, message)) 27 | status(Json.toJson(JsValueError(code, Some(message)))) 28 | } 29 | 30 | /** Build a JSON response with error infomation. */ 31 | def toResult(ex: Throwable): Result = { 32 | val message = this.message.getOrElse("An error occurred in the client.") 33 | logger.error("code:%d, message:%s".format(code, message), ex) 34 | status(Json.toJson(JsValueError(code, Some(message)))) 35 | } 36 | } 37 | 38 | trait Errors { 39 | val E_NOT_FOUND = Error(NotFound, NOT_FOUND, Some("Not found resource.")) 40 | val E_BAD_REQUEST = Error(BadRequest, BAD_REQUEST, Some("Bad request.")) 41 | val E_AUTHENTICATION = Error(Unauthorized, UNAUTHORIZED, Some("Authentication failure.")) 42 | val E_AUTHRIZATION = Error(Unauthorized, UNAUTHORIZED, Some("Authorization failure.")) 43 | val E_INTERNAL_SERVER = Error(InternalServerError, INTERNAL_SERVER_ERROR, Some("Internal server error.")) 44 | 45 | import scala.language.implicitConversions 46 | implicit def convert(v: Error): Result = v.toResult 47 | } 48 | 49 | object Errors extends Errors 50 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/model/Converter.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.model 10 | 11 | import scala.reflect.ClassTag 12 | import scala.collection.immutable.ListMap 13 | 14 | /** The data converter. */ 15 | trait Converter[-A, B] { 16 | def convert(o: A): B 17 | } 18 | 19 | /** The factory object for converter. */ 20 | object Converter extends TableDefaultConverter { 21 | def apply[A, B](f: A => B): Converter[A, B] = new Converter[A, B] { 22 | def convert(o: A): B = f(o) 23 | } 24 | } 25 | 26 | /** Default Serializers. */ 27 | trait TableDefaultConverter { 28 | /** Convert to Same Type. */ 29 | implicit def SameTypeConv[A <: AnyVal]: Converter[A, A] = new Converter[A, A] { 30 | def convert(v: A) = v 31 | } 32 | 33 | /** Serializer for Option. */ 34 | implicit def OptionConv[A, B](implicit fmt: Converter[A, B]): Converter[Option[A], Option[B]] = 35 | new Converter[Option[A], Option[B]] { 36 | def convert(v: Option[A]) = v match { 37 | case Some(value) => Some(fmt.convert(value)) 38 | case None => None 39 | } 40 | } 41 | 42 | /** Serializer for Seq[T] types. */ 43 | implicit def SeqConv[A: ClassTag, B: ClassTag](implicit fmt: Converter[A, B]): Converter[Seq[A], Seq[B]] = 44 | new Converter[Seq[A], Seq[B]] { 45 | def convert(itr: Seq[A]) = itr.foldLeft(Seq.empty[B]){ 46 | (prev, v) => prev :+ fmt.convert(v) 47 | } 48 | } 49 | 50 | /** 51 | * Serializer for Map[String, T] types. 52 | */ 53 | implicit def MapConv[A, B](implicit fmt: Converter[A, B]): Converter[Map[String, A], Map[String, B]] = 54 | new Converter[Map[String, A], Map[String, B]] { 55 | def convert(itr: Map[String, A]) = itr.foldLeft(ListMap.empty[String, B]){ 56 | case (prev, (k, v)) => prev + (k -> fmt.convert(v)) 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /framework/ixias-aws-s3/src/main/scala/ixias/aws/s3/model/FileSilo.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.s3.model 10 | 11 | import ixias.model._ 12 | import ixias.util.Enum 13 | 14 | // Silo configuration for partitioning data 15 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 16 | trait FileSilo[K <: @@[_, _]] { 17 | 18 | type Id = K 19 | 20 | /** directory seperator as string */ 21 | val DIRECTORY_SEPARATOR = """/""" 22 | 23 | /** 24 | * Build division unit of silo 25 | */ 26 | def silo(id: Id): String 27 | } 28 | 29 | // For String type Id 30 | //~~~~~~~~~~~~~~~~~~~~ 31 | trait FileSiloAsString[K <: @@[String, _]] extends FileSilo[K] { 32 | 33 | /** 34 | * Build division unit of silo 35 | */ 36 | def silo(id: Id): String = id 37 | } 38 | 39 | // For Long type Id 40 | //~~~~~~~~~~~~~~~~~~~ 41 | trait FileSiloAsLong[K <: @@[Long, _]] extends FileSilo[K] { 42 | 43 | // --[ Properties ]----------------------------------------------------------- 44 | /** division unit */ 45 | val divUnit: DivUnit 46 | 47 | // --[ Enum: silo division unit ]------------------------------------------- 48 | sealed abstract class DivUnit extends Enum 49 | object DivUnit extends Enum.Of[DivUnit] { 50 | case object IS_DIV_NONE extends DivUnit 51 | case object IS_DIV_100 extends DivUnit 52 | case object IS_DIV_10000 extends DivUnit 53 | } 54 | 55 | // --[ Methods ]------------------------------------------------------------ 56 | /** 57 | * Build division unit of silo 58 | */ 59 | def silo(id: Id): String = { 60 | val tok = "%04d".format(id % 10000) 61 | val mid = tok.drop(2) 62 | val sid = tok.take(2) 63 | (divUnit match { 64 | case DivUnit.IS_DIV_NONE => Seq( id.toString) 65 | case DivUnit.IS_DIV_100 => Seq( sid, id.toString) 66 | case DivUnit.IS_DIV_10000 => Seq(mid, sid, id.toString) 67 | }).mkString(DIRECTORY_SEPARATOR) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/util/SlickToolProvider.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.util 10 | 11 | import scala.concurrent.Future 12 | import slick.jdbc.JdbcProfile 13 | import slick.jdbc.meta.MTable 14 | 15 | import ixias.persistence.SlickProfile 16 | import ixias.persistence.model.Table 17 | 18 | /** 19 | * The utility tool to manage database with using Slick library. 20 | */ 21 | trait SlickToolProvider[P <: JdbcProfile] extends SlickProfile[P] { 22 | 23 | /** 24 | * Show create table SQL statements. 25 | */ 26 | def showCreateTable[T <: Table[_, P]](table: T): Future[Unit] = 27 | SlickDBAction(table) { case (_, slick) => 28 | import driver.api._ 29 | slick.asInstanceOf[T#BasicQuery] 30 | .schema.create.statements.foreach(println) 31 | Future.successful(()) 32 | } 33 | 34 | /** 35 | * Create database table by specified table schema. 36 | */ 37 | def createTable[T <: Table[_, P]](table: T): Future[Unit] = 38 | SlickRunDBAction(table) { slick => 39 | import driver.api._ 40 | for { 41 | tables <- MTable.getTables 42 | _ <- tables.exists(_.name.name == slick.baseTableRow.tableName) match { 43 | case false => slick.asInstanceOf[T#BasicQuery].schema.create 44 | case true => DBIO.successful(Unit) 45 | } 46 | } yield () 47 | } 48 | 49 | /** 50 | * Drop database table by specified table schema. 51 | */ 52 | def dropTable[T <: Table[_, P]](table: T): Future[Unit] = 53 | SlickRunDBAction(table) { slick => 54 | import driver.api._ 55 | for { 56 | tables <- MTable.getTables 57 | _ <- tables.exists(_.name.name == slick.baseTableRow.tableName) match { 58 | case true => slick.asInstanceOf[T#BasicQuery].schema.drop 59 | case false => DBIO.successful(Unit) 60 | } 61 | } yield () 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /framework/ixias-mail/src/main/scala/ixias/EmailClientViaTwillio.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.mail 10 | 11 | import java.util.ArrayList 12 | import javax.inject.Singleton 13 | import scala.util.{ Success, Failure } 14 | import scala.concurrent.{ Future, ExecutionContext } 15 | 16 | import org.apache.http.NameValuePair 17 | import org.apache.http.message.BasicNameValuePair 18 | import com.twilio.sdk.TwilioRestClient 19 | import com.twilio.sdk.resource.instance.Message 20 | 21 | // Send an email(SMS) via Twillio REST API 22 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 | @Singleton 24 | class EmailClientViaTwillio extends EmailClient with EmailConfig { 25 | 26 | /** 27 | * Send an email with the provided data. 28 | */ 29 | override def send(to: UserEmail, tpl: EmailTemplate[_]) 30 | (implicit ctx: ExecutionContext): Future[String] = 31 | for { 32 | from <- Future.fromTry(getTwillioFrom()) 33 | message <- send(to, UserEmail(from), tpl) 34 | } yield message 35 | 36 | /** 37 | * Send an email with the provided data. 38 | */ 39 | override def send(to: UserEmail, from: UserEmail, tpl: EmailTemplate[_]) 40 | (implicit ctx: ExecutionContext): Future[String] = 41 | Future.fromTry(for { 42 | sid <- getTwillioSid() 43 | token <- getTwillioAuthToken() 44 | } yield { 45 | val client = new TwilioRestClient(sid, token) 46 | val mParams = new ArrayList[NameValuePair]() 47 | mParams.add(new BasicNameValuePair("To", to.address)) 48 | mParams.add(new BasicNameValuePair("From", from.address)) 49 | mParams.add(new BasicNameValuePair("Body", tpl.getBodySMSText(to, from).get)) 50 | val message: Message = client.getAccount().getMessageFactory().create(mParams) 51 | message.getBody() 52 | }) andThen { 53 | case Success(_) => logger.info("[SUCCESS] to=" + to.address) 54 | case Failure(ex) => logger.error("[FAILURE] to=" + to.address, ex) 55 | } recover { 56 | case _: Throwable if tpl.silent => "" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/SlickRepository.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence 10 | 11 | import slick.jdbc.JdbcProfile 12 | import ixias.model.{ @@, EntityModel } 13 | import ixias.persistence.lifted._ 14 | import ixias.persistence.backend.SlickBackend 15 | import ixias.persistence.action.SlickDBActionProvider 16 | 17 | /** 18 | * The profile for persistence with using the Slick library. 19 | */ 20 | trait SlickProfile[P <: JdbcProfile] 21 | extends Profile with SlickDBActionProvider[P] { self => 22 | 23 | /** The type of slick driver */ 24 | type Driver = P 25 | 26 | /** The type of database objects. */ 27 | type Database = P#Backend#Database 28 | 29 | /** The back-end type required by this profile */ 30 | type Backend = SlickBackend[P] 31 | 32 | /** The configured driver. */ 33 | protected val driver: Driver 34 | 35 | /** The back-end implementation for this profile */ 36 | protected lazy val backend = SlickBackend(driver) 37 | 38 | /** Database Action Helpers */ 39 | protected val DBAction = SlickDBAction 40 | protected val RunDBAction = SlickRunDBAction 41 | 42 | /** 43 | * The API for using the utility methods with a single import statement. 44 | * This provides the repository's implicits, the Database connections, 45 | * and commonly types and objects. 46 | */ 47 | trait API extends super.API 48 | with driver.API 49 | with SlickQueryOps 50 | with SlickColumnTypeOps[P] 51 | with SlickRepOps[P] { 52 | lazy val driver = self.driver 53 | } 54 | trait APIUnsafe extends API with SlickRepUnsafeOps[P] 55 | val api: API = new API {} 56 | val apiUnsafe: APIUnsafe = new APIUnsafe {} 57 | } 58 | 59 | /** 60 | * The repository for persistence with using the Slick library. 61 | */ 62 | trait SlickRepository[K <: @@[_, _], M <: EntityModel[K], P <: JdbcProfile] 63 | extends Repository[K, M] with SlickProfile[P] { 64 | trait API extends super.API 65 | with SlickDBIOActionOps[K, M] 66 | override val api: API = new API {} 67 | } 68 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/lifted/SlickRepUnsafeOps.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.lifted 10 | 11 | import ixias.model._ 12 | import slick.jdbc.JdbcProfile 13 | import scala.language.implicitConversions 14 | 15 | trait SlickRepUnsafeOps[P <: JdbcProfile] extends SlickRepOps[P] 16 | { 17 | import driver.api._ 18 | 19 | implicit def toByteSlickRep[T](v: Byte @@ T): slick.lifted.Rep[Byte] = the[Identity[Byte @@ T]].unwrap(v) 20 | implicit def toShortSlickRep[T](v: Short @@ T): slick.lifted.Rep[Short] = the[Identity[Short @@ T]].unwrap(v) 21 | implicit def toIntSlickRep[T](v: Int @@ T): slick.lifted.Rep[Int] = the[Identity[Int @@ T]].unwrap(v) 22 | implicit def toLongSlickRep[T](v: Long @@ T): slick.lifted.Rep[Long] = the[Identity[Long @@ T]].unwrap(v) 23 | implicit def toBigDecimalSlickRep[T](v: BigDecimal @@ T): slick.lifted.Rep[BigDecimal] = the[Identity[BigDecimal @@ T]].unwrap(v) 24 | implicit def toStringSlickRep[T](v: String @@ T): slick.lifted.Rep[String] = the[Identity[String @@ T]].unwrap(v) 25 | 26 | implicit def toByteSlickRep[T](v: Option[ Byte @@ T]): slick.lifted.Rep[Option[Byte]] = v.map(the[Identity[Byte @@ T]].unwrap) 27 | implicit def toShortSlickRep[T](v: Option[ Short @@ T]): slick.lifted.Rep[Option[Short]] = v.map(the[Identity[Short @@ T]].unwrap) 28 | implicit def toIntSlickRep[T](v: Option[ Int @@ T]): slick.lifted.Rep[Option[Int]] = v.map(the[Identity[Int @@ T]].unwrap) 29 | implicit def toLongSlickRep[T](v: Option[ Long @@ T]): slick.lifted.Rep[Option[Long]] = v.map(the[Identity[Long @@ T]].unwrap) 30 | implicit def toBigDecimalSlickRep[T](v: Option[BigDecimal @@ T]): slick.lifted.Rep[Option[BigDecimal]] = v.map(the[Identity[BigDecimal @@ T]].unwrap) 31 | implicit def toStringSlickRep[T](v: Option[ String @@ T]): slick.lifted.Rep[Option[String]] = v.map(the[Identity[String @@ T]].unwrap) 32 | } 33 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/json/YearMonthReads.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.json 10 | 11 | import java.time.{ YearMonth, LocalDate, Instant, Clock, ZoneOffset } 12 | import java.time.temporal.UnsupportedTemporalTypeException 13 | import java.time.format.{ DateTimeFormatter, DateTimeParseException } 14 | import play.api.libs.json._ 15 | import scala.language.implicitConversions 16 | 17 | object YearMonthReads extends EnvReads { 18 | 19 | /** Instance of year-month based on formatter. */ 20 | implicit def YearMonthFormatterParser(formatter: DateTimeFormatter): TemporalParser[YearMonth] = 21 | new TemporalParser[YearMonth] { 22 | def parse(input: String): Option[YearMonth] = try { 23 | Some(YearMonth.parse(input, formatter)) 24 | } catch { 25 | case _: DateTimeParseException => None 26 | case _: UnsupportedTemporalTypeException => None 27 | } 28 | } 29 | 30 | /** 31 | * Reads for the `java.time.YearMonth` type. 32 | */ 33 | def yearMonthReads[T](parsing: T, corrector: String => String = identity)(implicit p: T => TemporalParser[YearMonth]): Reads[YearMonth] = 34 | new Reads[YearMonth] { 35 | def reads(json: JsValue): JsResult[YearMonth] = json match { 36 | case JsNumber(d) => JsSuccess(YearMonth.from(epoch(d.toLong))) 37 | case JsString(s) => p(parsing).parse(corrector(s)) match { 38 | case Some(d) => JsSuccess(d) 39 | case _ => JsError(Seq(JsPath -> 40 | Seq(JsonValidationError("error.expected.date.isoformat", parsing)))) 41 | } 42 | case _ => JsError(Seq(JsPath -> 43 | Seq(JsonValidationError("error.expected.date")))) 44 | } 45 | 46 | @inline def epoch(millis: Long): LocalDate = LocalDate.now( 47 | Clock.fixed(Instant.ofEpochMilli(millis), ZoneOffset.UTC) 48 | ) 49 | } 50 | 51 | /** 52 | * The default typeclass to reads `java.time.YearMonth` from JSON. 53 | */ 54 | implicit val DefaultYearMonthReads = 55 | yearMonthReads(DateTimeFormatter.ofPattern("yyyy-MM")) 56 | } 57 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/model/Entity.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.model 10 | 11 | import scala.reflect.runtime.universe._ 12 | 13 | /** Entity's id Status */ 14 | trait IdStatus 15 | object IdStatus { 16 | trait Empty extends IdStatus 17 | trait Exists extends IdStatus 18 | } 19 | 20 | /** The Entity */ 21 | final case class Entity[K <: @@[_, _], +M <: EntityModel[K], S <: IdStatus](v: M) { 22 | 23 | /** The entity data model */ 24 | type Model <: M 25 | 26 | /** The status of entity's identity */ 27 | type IdStatus = S 28 | 29 | /** get id value when id is exists */ 30 | def id(implicit ev: S =:= IdStatus.Exists): K = v.id.get 31 | 32 | /** check whether exists entity id value */ 33 | def hasId(implicit ev: TypeTag[IdStatus]): Boolean = 34 | ev.tpe =:= typeOf[IdStatus.Exists] 35 | 36 | /** Builds a new `Entity` by applying a function to values. */ 37 | @inline def map[M2 <: EntityModel[K]](f: M => M2): Entity[K, M2, S] = new Entity(f(v)) 38 | } 39 | 40 | // Companion object for Entity 41 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 42 | object Entity { 43 | 44 | // Entity with no identity. 45 | //~~~~~~~~~~~~~~~~~~~~~~~~~~ 46 | type WithNoId[K <: @@[_, _], M <: EntityModel[K]] = Entity[K, M, IdStatus.Empty] 47 | object WithNoId { 48 | /** Create a entity object with no id. */ 49 | def apply[K <: @@[_, _], M <: EntityModel[K]](data: M): WithNoId[K, M] = 50 | data.id match { 51 | case None => new Entity(data) 52 | case Some(_) => throw new IllegalArgumentException("The entity's id is already set.") 53 | } 54 | } 55 | 56 | // Entity has embedded Id. 57 | //~~~~~~~~~~~~~~~~~~~~~~~~~~ 58 | type EmbeddedId[K <: @@[_, _], M <: EntityModel[K]] = Entity[K, M, IdStatus.Exists] 59 | object EmbeddedId { 60 | def apply[K <: @@[_, _], M <: EntityModel[K]](data: M): EmbeddedId[K, M] = 61 | data.id match { 62 | case Some(_) => new Entity(data) 63 | case None => throw new IllegalArgumentException("Could not found id on entity's data.") 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/mvc/DeviceDetection.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.mvc 10 | 11 | import play.api.mvc._ 12 | import play.api.libs.typedmap.TypedKey 13 | import org.uaparser.scala.Parser 14 | import scala.concurrent.{ Future, ExecutionContext } 15 | 16 | /** The request attributes. */ 17 | object DeviceDetectionAttrKey { 18 | val OS = TypedKey[org.uaparser.scala.OS]("OS") 19 | val Device = TypedKey[org.uaparser.scala.Device]("Device") 20 | val UserAgent = TypedKey[org.uaparser.scala.UserAgent]("UserAgent") 21 | val IsMobile = TypedKey[Boolean]("IsMobile") 22 | } 23 | 24 | /** 25 | * Provides the custom action to detect device by User-Agent 26 | */ 27 | trait DeviceDetectionBuilder extends ActionBuilder[Request, AnyContent] 28 | object DeviceDetectionBuilder { 29 | def apply(parser: BodyParser[AnyContent])(implicit ec: ExecutionContext): DeviceDetectionBuilder = 30 | new DeviceDetectionBuilderImpl(parser) 31 | } 32 | 33 | // Implementation for device detection. 34 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 35 | class DeviceDetectionBuilderImpl( 36 | val parser: BodyParser[AnyContent] 37 | )(implicit val executionContext: ExecutionContext) extends DeviceDetectionBuilder { 38 | 39 | val MOBILE_UA_REGEX = "(iPhone|webOS|iPod|Android|BlackBerry|mobile|SAMSUNG|IEMobile|OperaMobi)".r.unanchored 40 | 41 | /** Invoke the block. */ 42 | def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = 43 | request.headers.get("User-Agent") match { 44 | case None => block(request) 45 | case Some(ua) => block { 46 | val client = Parser.get.parse(ua) 47 | request 48 | .addAttr(DeviceDetectionAttrKey.OS, client.os) 49 | .addAttr(DeviceDetectionAttrKey.Device, client.device) 50 | .addAttr(DeviceDetectionAttrKey.UserAgent, client.userAgent) 51 | .addAttr(DeviceDetectionAttrKey.IsMobile, ua match { 52 | case MOBILE_UA_REGEX(_) => true 53 | case _ => false 54 | }) 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/lifted/SlickQueryOps.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.lifted 10 | 11 | import slick.ast.{ TypedType, Library } 12 | import slick.lifted.{ Rep, Query, FunctionSymbolExtensionMethods, CanBeQueryCondition } 13 | import ixias.persistence.model.Cursor 14 | 15 | import scala.language.higherKinds 16 | import scala.language.implicitConversions 17 | 18 | final case class SlickQueryTransformer[E, U, C[_]](val self: Query[E, U, C]) extends AnyVal { 19 | def seek(cursor: Cursor): Query[E, U, C] = 20 | cursor.limit match { 21 | case None => if (0 < cursor.offset) self.drop(cursor.offset) else self 22 | case Some(limit) => self.drop(cursor.offset).take(limit) 23 | } 24 | 25 | //-- [ Slick3.3 features ] --------------------------------------------------- 26 | /** 27 | * Applies the given filter, if the Option value is defined. 28 | * If the value is None, the filter will not be part of the query. 29 | */ 30 | def filterOpt[V, T : CanBeQueryCondition](optValue: Option[V])(f: (E, V) => T): Query[E, U, C] = 31 | optValue.map(v => self.withFilter(a => f(a, v))).getOrElse(self) 32 | 33 | /** 34 | * Applies the given filter function, if the boolean parameter `p` evaluates to true. 35 | * If not, the filter will not be part of the query. 36 | */ 37 | def filterIf[T : CanBeQueryCondition](p: Boolean)(f: E => T): Query[E, U, C] = 38 | if (p) self.withFilter(f) else self 39 | } 40 | 41 | final case class SlickQueryTransformerId[T <: ixias.model.@@[_, _], U, C[_]]( 42 | val self: Query[Rep[T], U, C] 43 | ) extends AnyVal { 44 | def distinctLength(implicit tm: TypedType[Int]): Rep[Int] = 45 | FunctionSymbolExtensionMethods 46 | .functionSymbolExtensionMethods(Library.CountDistinct) 47 | .column(self.toNode) 48 | } 49 | 50 | trait SlickQueryOps { 51 | implicit def toQueryTransformer[E, U, C[_]](a: Query[E, U, C]) = SlickQueryTransformer(a) 52 | implicit def toQueryTransformerId[T <: ixias.model.@@[_, _], U, C[_]](a: Query[Rep[T], U, Seq]) = SlickQueryTransformerId(a) 53 | } 54 | -------------------------------------------------------------------------------- /framework/ixias-play-auth/src/main/scala/ixias/play/api/auth/token/TokenViaSession.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.auth.token 10 | 11 | import play.api.mvc.{ Result, RequestHeader, Cookie, DiscardingCookie } 12 | import play.api.mvc.Cookie.SameSite 13 | import java.time.Duration 14 | import ixias.util.ConfigLoader 15 | 16 | case class TokenViaSession(val name: String) extends Token { 17 | import Token._ 18 | 19 | private implicit val sameSiteConfigLoader: ConfigLoader[Option[SameSite]] = 20 | ConfigLoader(_.getString).map(SameSite.parse) 21 | 22 | // The configuration 23 | def cookieName = config.get[String] (s"session.${name}.cookieName") 24 | def maxAge = config.get[Option[Duration]] (s"session.${name}.maxAge") 25 | def path = config.get[String] (s"session.${name}.path") 26 | def domain = config.get[Option[String]] (s"session.${name}.domain") 27 | def secure = config.get[Boolean] (s"session.${name}.secure") 28 | def httpOnly = config.get[Boolean] (s"session.${name}.httpOnly") 29 | def sameSite = config.get[Option[SameSite]] (s"session.${name}.sameSite") 30 | 31 | /** 32 | * Put a specified security token to storage. 33 | */ 34 | def put(token: AuthenticityToken)(result: Result)(implicit request: RequestHeader): Result = { 35 | val signed = SignedToken.unwrap(Token.signWithHMAC(token)) 36 | val maxAgeSecs = maxAge.map(_.getSeconds.toInt) 37 | val cookie = Cookie(cookieName, signed, maxAgeSecs, path, domain, secure, httpOnly, sameSite) 38 | result.withCookies(cookie) 39 | } 40 | 41 | /** 42 | * Discard a security token in storage. 43 | */ 44 | def discard(result: Result)(implicit request: RequestHeader): Result = 45 | result.discardingCookies(DiscardingCookie(cookieName)) 46 | 47 | /** 48 | * Extract a security token from storage. 49 | */ 50 | def extract(implicit request: RequestHeader): Option[AuthenticityToken] = 51 | for { 52 | signed <- request.cookies.get(cookieName).map(c => SignedToken(c.value)) 53 | token <- Token.verifyHMAC(signed) 54 | } yield token 55 | } 56 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/util/OrderingHelper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.util 10 | 11 | import scala.math.Ordering 12 | 13 | trait OrderingHelper { 14 | 15 | // --[ For Option ]----------------------------------------------------------- 16 | def noneFirstAsc [T](implicit o: Ordering[T]): Ordering[Option[T]] = Ordering.Option 17 | def noneFirstDesc [T](implicit o: Ordering[T]): Ordering[Option[T]] = noneFirstAsc(o.reverse) 18 | def noneLastDesc [T](implicit o: Ordering[T]): Ordering[Option[T]] = noneFirstAsc(o).reverse 19 | def noneLastAsc [T](implicit o: Ordering[T]): Ordering[Option[T]] = noneLastDesc(o.reverse) 20 | 21 | // --[ Ordering ]------------------------------------------------------------- 22 | /** 23 | * For Japanses String 24 | */ 25 | implicit val StringJP: Ordering[String] = Ordering.comparatorToOrdering( 26 | java.text.Collator.getInstance(java.util.Locale.JAPANESE) 27 | .asInstanceOf[java.util.Comparator[String]] 28 | ) 29 | 30 | /** 31 | * For java.time.YearMonth 32 | */ 33 | trait YearMonthOrdering extends Ordering[java.time.YearMonth] { 34 | def compare(x: java.time.YearMonth, y: java.time.YearMonth): Int = x compareTo y 35 | } 36 | implicit object YearMonth extends YearMonthOrdering 37 | 38 | /** 39 | * For java.time.LocalDate 40 | */ 41 | trait LocalDateOrdering extends Ordering[java.time.LocalDate] { 42 | def compare(x: java.time.LocalDate, y: java.time.LocalDate): Int = x compareTo y 43 | } 44 | implicit object LocalDate extends LocalDateOrdering 45 | 46 | /** 47 | * For java.time.LocalDateTime 48 | */ 49 | trait LocalDateTimeOrdering extends Ordering[java.time.LocalDateTime] { 50 | def compare(x: java.time.LocalDateTime, y: java.time.LocalDateTime): Int = x compareTo y 51 | } 52 | implicit object LocalDateTime extends LocalDateTimeOrdering 53 | 54 | /** 55 | * For java.time.Duration 56 | */ 57 | trait DurationOrdering extends Ordering[java.time.Duration] { 58 | def compare(x: java.time.Duration, y: java.time.Duration): Int = x compareTo y 59 | } 60 | implicit object Duration extends DurationOrdering 61 | } 62 | -------------------------------------------------------------------------------- /framework/ixias-play-auth/src/main/scala/ixias/play/api/auth/token/Token.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.auth.token 10 | 11 | import ixias.model._ 12 | import ixias.security.TokenSigner 13 | import ixias.util.Configuration 14 | import ixias.util.Logging 15 | import play.api.mvc.{ RequestHeader, Result } 16 | 17 | // The security token 18 | //~~~~~~~~~~~~~~~~~~~~ 19 | trait Token { 20 | import Token._ 21 | 22 | /** The configuration */ 23 | protected val config = Configuration() 24 | 25 | /** Put a specified security token to storage */ 26 | def put(token: AuthenticityToken)(result: Result)(implicit request: RequestHeader): Result 27 | 28 | /** Discard a security token in storage */ 29 | def discard(result: Result)(implicit request: RequestHeader): Result 30 | 31 | /** Extract a security token from storage */ 32 | def extract(implicit request: RequestHeader): Option[AuthenticityToken] 33 | } 34 | 35 | // Companion object 36 | //~~~~~~~~~~~~~~~~~~ 37 | object Token extends Logging { 38 | 39 | sealed trait Tag 40 | protected object Tag { 41 | trait SignedToken extends Token 42 | trait AuthenticityToken extends Token 43 | } 44 | type SignedToken = String @@ Tag.SignedToken 45 | type AuthenticityToken = String @@ Tag.AuthenticityToken 46 | val SignedToken = the[Identity[SignedToken]] 47 | val AuthenticityToken = the[Identity[AuthenticityToken]] 48 | 49 | /** The object that provides some cryptographic operations */ 50 | protected lazy val signer = TokenSigner() 51 | 52 | /** Verifies a given HMAC on a piece of data */ 53 | final def verifyHMAC(signedToken: SignedToken): Option[AuthenticityToken] = 54 | signer.verify(SignedToken.unwrap(signedToken)) match { 55 | case scala.util.Success(v) => Some(AuthenticityToken(v)) 56 | case scala.util.Failure(ex) => { 57 | logger.warn("Token's HMAC verification failed. %s", ex) 58 | None 59 | } 60 | } 61 | 62 | /** Signs the given String with HMAC-SHA1 using the secret token.*/ 63 | final def signWithHMAC(token: AuthenticityToken): SignedToken = 64 | SignedToken(signer.sign(AuthenticityToken.unwrap(token))) 65 | } 66 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/model/Table.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.model 10 | 11 | import ixias.persistence.lifted._ 12 | import slick.jdbc.JdbcProfile 13 | 14 | trait Table[R, P <: JdbcProfile] { self => 15 | 16 | //-- [ Required properties ] ------------------------------------------------- 17 | /** The configured driver. */ 18 | val driver: P 19 | 20 | /** The map of DSN as string. */ 21 | val dsn: Map[String, DataSourceName] 22 | 23 | /** The table query. */ 24 | val query: Query 25 | 26 | /** The alias for DSN */ 27 | val DataSourceName = ixias.persistence.model.DataSourceName 28 | 29 | //-- [ Table Manifest ] ------------------------------------------------------ 30 | /** The type of table row. */ 31 | type Record = R 32 | 33 | /** A Tag marks a specific row represented by an AbstractTable instance. */ 34 | type Tag = slick.lifted.Tag 35 | 36 | /** The type of all table row objects. */ 37 | type Table <: driver.Table[Record] 38 | type BasicTable = driver.Table[Record] 39 | 40 | //-- [ Table Query ] --------------------------------------------------------- 41 | /** 42 | * Represents a database table. Implementation class add extension methods to TableQuery 43 | * for operations that can be performed on tables but not on arbitrary queries. 44 | */ 45 | type Query <: slick.lifted.TableQuery[Table] 46 | type BasicQuery = slick.lifted.TableQuery[Table] 47 | 48 | //-- [ Utility Methods ] ----------------------------------------------------- 49 | /** 50 | * The API for using the utility methods with a single import statement. 51 | * This provides the repository's implicits, the Database connections, 52 | * and commonly types and objects. 53 | */ 54 | trait API extends driver.API 55 | with Aliases 56 | with ExtensionMethods 57 | with SlickColumnOptionOps 58 | with SlickColumnTypeOps[P] 59 | with SlickRepOps[P] { 60 | lazy val driver = self.driver 61 | } 62 | trait APIUnsafe extends API with SlickRepUnsafeOps[P] 63 | val api: API = new API {} 64 | val apiUnsafe: APIUnsafe = new APIUnsafe {} 65 | } 66 | 67 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/backend/AmazonQLDBConfig.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.backend 10 | 11 | import scala.util.Try 12 | import com.amazonaws.regions.Regions 13 | import com.amazonaws.auth.{ AWSCredentials, BasicAWSCredentials } 14 | 15 | import ixias.persistence.model.DataSourceName 16 | import ixias.persistence.backend.BasicDatabaseConfig 17 | 18 | trait AmazonQLDBConfig extends BasicDatabaseConfig { 19 | 20 | // --[ Properties ]----------------------------------------------------------- 21 | // The keys of configuration 22 | protected val CF_QLDB_ACCESS_KEY = "access_key_id" 23 | protected val CF_QLDB_SECRET_KEY = "secret_access_key" 24 | protected val CF_QLDB_REGION = "region" 25 | protected val CF_QLDB_LEDGER_NAME = "ledger_name" 26 | 27 | // --[ Methods ]-------------------------------------------------------------- 28 | /** 29 | * Gets the AWS credentials object. 30 | */ 31 | def getAWSCredentials(implicit dsn: DataSourceName): Try[AWSCredentials] = 32 | for { 33 | akey <- getAWSAccessKeyId 34 | skey <- getAWSSecretKey 35 | } yield new BasicAWSCredentials(akey, skey) 36 | 37 | /** 38 | * Gets the AWS access key ID for this credentials object. 39 | */ 40 | protected def getAWSAccessKeyId(implicit dsn: DataSourceName): Try[String] = 41 | Try(readValue( 42 | _.get[Option[String]](CF_QLDB_ACCESS_KEY)).get 43 | ) 44 | 45 | /** 46 | * Gets the AWS secret access key for this credentials object. 47 | */ 48 | protected def getAWSSecretKey(implicit dsn: DataSourceName): Try[String] = 49 | Try(readValue( 50 | _.get[Option[String]](CF_QLDB_SECRET_KEY)).get 51 | ) 52 | 53 | /** 54 | * Gets a region enum corresponding to the given region name. 55 | */ 56 | def getAWSRegion(implicit dsn: DataSourceName): Try[Regions] = 57 | Try(Regions.fromName(readValue( 58 | _.get[Option[String]](CF_QLDB_REGION)).get 59 | )) 60 | 61 | /** 62 | * Gets the name of the Ledger 63 | */ 64 | def getLedgerName(implicit dsn: DataSourceName): Try[String] = 65 | Try(readValue( 66 | _.get[Option[String]](CF_QLDB_LEDGER_NAME)).get 67 | ) 68 | } 69 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/util/Logging.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.util 10 | 11 | import scala.reflect.ClassTag 12 | import org.slf4j.{ LoggerFactory, Logger => Slf4jLogger } 13 | 14 | /** 15 | * A Logger object is used to log messages for a specific system or application component. 16 | */ 17 | trait Logging { 18 | protected[this] lazy val logger = { 19 | val n = getClass.getName 20 | val cln = if (n endsWith "$") n.substring(0, n.length - 1) else n 21 | new Logger(LoggerFactory.getLogger(cln)) 22 | } 23 | } 24 | 25 | /** 26 | * The Logger is a convenient and performant logging library wrapping SLF4J. 27 | */ 28 | sealed class Logger(val slf4jLogger: Slf4jLogger) { 29 | 30 | @inline def isDebugEnabled = slf4jLogger.isDebugEnabled() 31 | 32 | // --[ Methods ]----------------------------------------------------------- 33 | @inline def error(msg: => String) { if (slf4jLogger.isErrorEnabled) slf4jLogger.error(msg) } 34 | @inline def warn(msg: => String) { if (slf4jLogger.isWarnEnabled) slf4jLogger.warn(msg) } 35 | @inline def info(msg: => String) { if (slf4jLogger.isInfoEnabled) slf4jLogger.info(msg) } 36 | @inline def debug(msg: => String) { if (slf4jLogger.isDebugEnabled) slf4jLogger.debug(msg) } 37 | @inline def trace(msg: => String) { if (slf4jLogger.isTraceEnabled) slf4jLogger.trace(msg) } 38 | 39 | // --[ Methods ]----------------------------------------------------------- 40 | @inline def error(msg: => String, t: Throwable) { if (slf4jLogger.isErrorEnabled) slf4jLogger.error(msg, t) } 41 | @inline def warn(msg: => String, t: Throwable) { if (slf4jLogger.isWarnEnabled) slf4jLogger.warn(msg, t) } 42 | @inline def info(msg: => String, t: Throwable) { if (slf4jLogger.isInfoEnabled) slf4jLogger.info(msg, t) } 43 | @inline def debug(msg: => String, t: Throwable) { if (slf4jLogger.isDebugEnabled) slf4jLogger.debug(msg, t) } 44 | @inline def trace(msg: => String, t: Throwable) { if (slf4jLogger.isTraceEnabled) slf4jLogger.trace(msg, t) } 45 | } 46 | 47 | /** 48 | * The logger's companion object 49 | */ 50 | object Logger { 51 | def apply[T](implicit ct: ClassTag[T]): Logger = 52 | new Logger(LoggerFactory.getLogger(ct.runtimeClass)) 53 | } 54 | -------------------------------------------------------------------------------- /framework/ixias-aws-s3/src/main/scala/ixias/aws/s3/model/CloudFrontUrl.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.s3.model 10 | 11 | import play.api.libs.json._ 12 | 13 | /** 14 | * Clound front URL 15 | */ 16 | case class CloudFrontUrl( 17 | meta: File#EmbeddedId, 18 | width: Option[Int] = None, 19 | height: Option[Int] = None, 20 | responsive: Boolean = false, 21 | format: Option[UrlSigner.Request.Format] = None, 22 | custom: Seq[(String, String)] = Nil 23 | )(implicit val dsn: ixias.aws.s3.backend.DataSourceName) { 24 | import UrlSigner.Request.Ratio 25 | 26 | /** 27 | * Generate request of file resizing 28 | */ 29 | lazy val genUrlSignerRequest: Seq[UrlSigner.Request] = 30 | responsive match { 31 | case false => Seq(UrlSigner.Request(width, height, None, format, custom)) 32 | case true => Seq( 33 | UrlSigner.Request(width, height, Some(Ratio.IS_1x), format, custom), 34 | UrlSigner.Request(width, height, Some(Ratio.IS_2x), format, custom) 35 | ) 36 | } 37 | } 38 | 39 | // The companion object 40 | //~~~~~~~~~~~~~~~~~~~~~~ 41 | object CloudFrontUrl { 42 | import UrlSigner.Request.Ratio._ 43 | import UrlSigner.getSigendCloudFrontUrl 44 | 45 | /** 46 | * Serializer for CloudFrontUrl 47 | */ 48 | implicit object writes extends Writes[CloudFrontUrl] { 49 | def writes(data: CloudFrontUrl) = { 50 | implicit val dsn = data.dsn 51 | JsObject(Seq( 52 | Some("fid" -> JsNumber(data.meta.id)), 53 | Some("src" -> JsString(getSigendCloudFrontUrl(data.meta, data.genUrlSignerRequest.head).toString)), 54 | data.responsive match { 55 | case false => None 56 | case true => Some("srcset" -> JsString( 57 | data.genUrlSignerRequest.map( 58 | resize => "%s %s".format( 59 | getSigendCloudFrontUrl(data.meta, resize)(data.dsn).toString, 60 | resize.ratio.getOrElse(IS_1x).value 61 | ) 62 | ).mkString(", ") 63 | )) 64 | }, 65 | data.width .map("width" -> JsNumber(_)), 66 | data.height.map("height" -> JsNumber(_)) 67 | ).flatten) 68 | } 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/mvc/binder/Cursor.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.mvc.binder 10 | 11 | import play.api.mvc.QueryStringBindable 12 | import ixias.play.api.mvc.QueryStringHelper 13 | 14 | trait CursorBindable { 15 | 16 | // --[ Alias ]---------------------------------------------------------------- 17 | val Cursor = ixias.persistence.model.Cursor 18 | type Cursor = ixias.persistence.model.Cursor 19 | 20 | // -- [ QueryStringBindable ] ------------------------------------------------ 21 | /** 22 | * QueryString binder for `Cursor` 23 | */ 24 | case class queryStringBindableCursor( 25 | limitDefault: Int, // The number of results: default value 26 | limitMax: Int // The number of results: maximum value 27 | ) extends QueryStringBindable[Cursor] with QueryStringHelper { 28 | 29 | /** 30 | * Unbind a query string parameter. 31 | */ 32 | def unbind(key: String, value: Cursor): String = 33 | Seq( 34 | key + ".offset" -> Option(value.offset), 35 | key + ".limit" -> value.limit 36 | ).collect({ 37 | case (key, Some(v)) if v > 0 => "%s=%d".format(key, v) 38 | }).mkString("&") 39 | 40 | /** 41 | * Bind a query string parameter. 42 | */ 43 | def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, Cursor]] = { 44 | implicit val _params = params 45 | (for { 46 | v1 <- implicitly[QueryStringBindable[Long]]._bindOption(key + ".offset") 47 | v2 <- implicitly[QueryStringBindable[Long]]._bindOption(key + ".limit") 48 | } yield v1.filter(_ > 0) -> v2.filter(_ > 0) match { 49 | case (Some(v1), Some(v2)) => Cursor(v1, Some(v2)) 50 | case (None, Some(v2)) => Cursor(0L, Some(v2)) 51 | case (Some(v1), None) => Cursor(v1, Some(limitDefault.toLong)) 52 | case _ => Cursor(0L, Some(limitDefault.toLong)) 53 | }) match { 54 | case Left(v) => Some(Left(v)) 55 | case Right(cur) => cur.limit.map(_ > limitMax) match { 56 | case Some(true) => Some(Right(cur.copy(limit = Some(limitMax.toLong)))) 57 | case _ => Some(Right(cur)) 58 | } 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/databind/EnumBitFlagsSerializerModule.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.databind 10 | 11 | import com.fasterxml.jackson.databind._ 12 | import com.fasterxml.jackson.databind.`type`.CollectionLikeType 13 | import com.fasterxml.jackson.databind.jsontype.TypeSerializer 14 | import com.fasterxml.jackson.databind.ser.Serializers 15 | 16 | import com.fasterxml.jackson.core.JsonGenerator 17 | import com.fasterxml.jackson.module.scala.JacksonModule 18 | import ixias.util.EnumBitFlags 19 | 20 | // Serialize Objects of `EnumBitFlags` 21 | // into JSON, using provided JsonGenerator. 22 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 | case class EnumBitFlagsSerializer( 24 | collectionType: CollectionLikeType 25 | ) extends JsonSerializer[Seq[EnumBitFlags]] { 26 | def serialize(value: Seq[EnumBitFlags], jgen: JsonGenerator, provider: SerializerProvider): Unit = { 27 | val elcls = collectionType.getContentType.getRawClass 28 | val clazz = Class.forName(elcls.getName + "$") 29 | val module = clazz.getField("MODULE$").get(null) 30 | val method = clazz.getMethod("toBitset", classOf[Seq[_]]) 31 | val bitset = method.invoke(module, value.asInstanceOf[AnyRef]) 32 | jgen.writeNumber(bitset.asInstanceOf[Long]) 33 | } 34 | } 35 | 36 | // Resolver to serve serializer 37 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 38 | object EnumBitFlagsSerializerResolver extends Serializers.Base { 39 | private val SYMBOL = classOf[Seq[_]] 40 | private val CONTENT = classOf[EnumBitFlags] 41 | override def findCollectionLikeSerializer( 42 | config: SerializationConfig, 43 | collectionType: CollectionLikeType, 44 | beanDescription: BeanDescription, 45 | elementTypeSerializer: TypeSerializer, 46 | elementSerializer: JsonSerializer[Object] 47 | ): JsonSerializer[_] = ( 48 | (SYMBOL isAssignableFrom collectionType.getRawClass) && 49 | (CONTENT isAssignableFrom collectionType.getContentType.getRawClass) 50 | ) match { 51 | case true => EnumBitFlagsSerializer(collectionType) 52 | case false => null 53 | } 54 | } 55 | 56 | // Jackson Module Definition 57 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 58 | trait EnumBitFlagsSerializerModule extends JacksonModule { 59 | this += { _ addSerializers EnumBitFlagsSerializerResolver } 60 | } 61 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/databind/EnumBitFlagsDeserializerModule.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.databind 10 | 11 | import com.fasterxml.jackson.databind._ 12 | import com.fasterxml.jackson.databind.deser.Deserializers 13 | import com.fasterxml.jackson.databind.jsontype.TypeDeserializer 14 | import com.fasterxml.jackson.databind.`type`.CollectionLikeType 15 | import com.fasterxml.jackson.core.JsonParser 16 | import com.fasterxml.jackson.module.scala.JacksonModule 17 | import ixias.util.EnumBitFlags 18 | 19 | // Deserialize Objects of `EnumBitFlags` 20 | // from JSON, using provided JsonParser. 21 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | case class EnumBitFlagsDeserializer( 23 | collectionType: CollectionLikeType 24 | ) extends JsonDeserializer[Seq[EnumBitFlags]] { 25 | override def deserialize(p: JsonParser, ctxt: DeserializationContext): Seq[EnumBitFlags] = { 26 | val elcls = collectionType.getContentType.getRawClass 27 | val clazz = Class.forName(elcls.getName + "$") 28 | val module = clazz.getField("MODULE$").get(null) 29 | val method = clazz.getMethod("apply", classOf[Long]) 30 | val enum = method.invoke(module, p.getValueAsLong.asInstanceOf[AnyRef]) 31 | enum.asInstanceOf[Seq[EnumBitFlags]] 32 | } 33 | } 34 | 35 | // Resolver to serve deserializer 36 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 37 | object EnumBitFlagsDeserializerResolver extends Deserializers.Base { 38 | private val SYMBOL = classOf[Seq[_]] 39 | private val CONTENT = classOf[EnumBitFlags] 40 | override def findCollectionLikeDeserializer( 41 | collectionType: CollectionLikeType, 42 | config: DeserializationConfig, 43 | beanDesc: BeanDescription, 44 | elementTypeDeserializer: TypeDeserializer, 45 | elementDeserializer: JsonDeserializer[_] 46 | ): JsonDeserializer[_] = ( 47 | (SYMBOL isAssignableFrom collectionType.getRawClass) && 48 | (CONTENT isAssignableFrom collectionType.getContentType.getRawClass) 49 | ) match { 50 | case true => EnumBitFlagsDeserializer(collectionType) 51 | case false => null 52 | } 53 | } 54 | 55 | // Jackson Module Definition 56 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 57 | trait EnumBitFlagsDeserializerModule extends JacksonModule { 58 | this += { _ addDeserializers EnumBitFlagsDeserializerResolver } 59 | } 60 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/util/json/JsonEnvWrites.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.util.json 10 | 11 | import play.api.libs.json._ 12 | import play.api.libs.json.EnvWrites 13 | 14 | /** 15 | * Writes Conbinator for type conversion in service 16 | */ 17 | trait JsonEnvWrites extends EnvWrites { 18 | 19 | /** 20 | * Serializer forshapeless.tag.@@[Long, _] 21 | */ 22 | implicit def TagLongWrites[T] = 23 | new Writes[shapeless.tag.@@[Long, T]] { 24 | def writes(tag: shapeless.tag.@@[Long, T]) = JsNumber(tag) 25 | } 26 | 27 | /** 28 | * Serializer forshapeless.tag.@@[String, _] 29 | */ 30 | implicit def TagStringWrites[T] = 31 | new Writes[shapeless.tag.@@[String, T]] { 32 | def writes(tag: shapeless.tag.@@[String, T]) = JsString(tag) 33 | } 34 | 35 | /** 36 | * Serializer for ixias.util.EnumStatus 37 | */ 38 | implicit def EnumStatusWrites[T <: ixias.util.EnumStatus] = 39 | new Writes[T] { 40 | def writes(v: T) = JsNumber(v.code) 41 | } 42 | 43 | /** 44 | * Serializer for ixias.util.EnumStatusAsstr 45 | */ 46 | implicit def EnumStatusAsStrWrites[T <: ixias.util.EnumStatusAsStr] = 47 | new Writes[T] { 48 | def writes(v: T) = JsString(v.code) 49 | } 50 | 51 | /** 52 | * Serializer for Seq[ixias.util.EnumBitFlags] 53 | */ 54 | implicit def EnumBitFlagsWrites[T <: ixias.util.EnumBitFlags] = 55 | new Writes[T] { 56 | def writes(v: T) = JsNumber(v.code) 57 | } 58 | 59 | /** 60 | * Serializer for ixias.persistence.model.Cursor 61 | */ 62 | implicit object CursorWrites extends Writes[ixias.persistence.model.Cursor] { 63 | def writes(cursor: ixias.persistence.model.Cursor) = 64 | JsObject(Seq( 65 | Some( "offset" -> JsNumber(cursor.offset)), 66 | cursor.limit.map("limit" -> JsNumber(_)) 67 | ).flatten) 68 | } 69 | 70 | /** 71 | * Serializer for java.time.YearMonth 72 | */ 73 | implicit object YearMonthWrites extends Writes[java.time.YearMonth] { 74 | def writes(yearMonth: java.time.YearMonth) = 75 | JsObject(Seq( 76 | "year" -> JsNumber(yearMonth.getYear), 77 | "month" -> JsNumber(yearMonth.getMonthValue), 78 | "text" -> JsString(yearMonth.format( 79 | java.time.format.DateTimeFormatter.ofPattern("yyyy-MM") 80 | )) 81 | )) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/model/SqlPrepareStatement.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.model 10 | 11 | import com.amazon.ion.IonValue 12 | 13 | /** 14 | * Typedef for Not-Nothing 15 | */ 16 | sealed trait NotNothing[-T] 17 | object NotNothing { 18 | implicit object NotNothing extends NotNothing[Any] 19 | implicit object YoureSupposedToSupplyAType extends NotNothing[Nothing] 20 | } 21 | 22 | /** 23 | * Preparation information for generating `SqlStatement` 24 | */ 25 | case class SqlPrepareStatement( 26 | val tableName: String, // Table name 27 | val baseQuery: String, // Query definition with reserved words 28 | val bindParams: Seq[IonValue] // Bind params for placeholder 29 | ) { 30 | 31 | //-- [ Constants ] ----------------------------------------------------------- 32 | val T_DDL_INSERT = """INSERT""".r 33 | val T_DDL_BIND_PHOLD = """\?""".r 34 | val T_TABLE_NAME = """__TABLE_NAME__""".r 35 | 36 | //-- [ Methods ] ------------------------------------------------------------- 37 | /** 38 | * Fixied `SqlStatement` 39 | */ 40 | def affectedDocs = { 41 | implicit val mctag = reflect.classTag[AffectedDocument] 42 | SqlStatement.ForMultiResult(query, bindParams) 43 | } 44 | 45 | /** 46 | * Fixied `SqlStatement` 47 | */ 48 | def result[A: NotNothing](implicit ctag: reflect.ClassTag[A]) = 49 | SqlStatement.ForMultiResult(query, bindParams) 50 | 51 | /** 52 | * Get query to be execution. 53 | */ 54 | def query = { 55 | // Whether it is specified reserved word to replace to table's name 56 | if (T_TABLE_NAME.findFirstIn(baseQuery).isEmpty) { 57 | throw new IllegalArgumentException( 58 | "The required reserved word `%s` is not specified in the baseQuery" 59 | .format(T_TABLE_NAME.regex) 60 | ) 61 | } 62 | // Verification number of parameters. 63 | if ( 64 | T_DDL_INSERT.findFirstIn(baseQuery).isEmpty && 65 | T_DDL_BIND_PHOLD.findAllIn(baseQuery).matchData.size != bindParams.size 66 | ) { 67 | throw new IllegalArgumentException( 68 | "The number of parameters specified for the baseQuery placeholder does not match. " 69 | + "baseQuery = %s, params = %s".format(baseQuery, bindParams) 70 | ) 71 | } 72 | // Build query 73 | T_TABLE_NAME.replaceAllIn(baseQuery, tableName) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /framework/ixias-aws-sns/src/main/scala/ixias/aws/sns/AmazonSNS.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.sns 10 | 11 | import scala.util.{ Try, Success, Failure } 12 | import scala.concurrent.{ Future, ExecutionContext } 13 | import com.amazonaws.services.sns.model.PublishResult 14 | 15 | import ixias.persistence.lifted.Aliases 16 | import ixias.persistence.dbio.Execution 17 | import ixias.util.Logging 18 | 19 | // Amazon SNS 20 | //~~~~~~~~~~~~ 21 | trait AmazonSNS extends Aliases with Logging { 22 | 23 | // --[ Alias ]---------------------------------------------------------------- 24 | /** The data source name */ 25 | val DataSourceName = ixias.aws.sns.backend.DataSourceName 26 | type DataSourceName = ixias.aws.sns.backend.DataSourceName 27 | implicit val dsn: DataSourceName 28 | 29 | // --[ Properties ]----------------------------------------------------------- 30 | /** The backend */ 31 | protected val backend = ixias.aws.sns.backend.AmazonSNSBackend 32 | 33 | /** The Execution Context */ 34 | protected implicit val ctx: ExecutionContext = Execution.Implicits.trampoline 35 | 36 | // --[ Methods ]-------------------------------------------------------------- 37 | /** 38 | * Sends a message to a topic's subscribed endpoints. 39 | */ 40 | def publish(message: String): Future[Seq[PublishResult]] = 41 | backend.isSkip(dsn) match { 42 | case true => { 43 | backend.getTopicARN(dsn) map { topic => 44 | logger.info("AWS-SNS :: skip to publish a message. topic = %s, message = %s".format(topic, message)) 45 | } 46 | Future.successful(Seq.empty) 47 | } 48 | case false => for { 49 | client <- backend.getClient(dsn) 50 | topicSeq <- Future.fromTry(backend.getTopicARN(dsn)) 51 | resultSeq <- Future.sequence { 52 | topicSeq map { topic => 53 | Future.fromTry { 54 | Try(client.publish(topic, message)) 55 | } andThen { 56 | case Success(result) => logger.info( 57 | "AWS-SNS :: publish a message. topic = %s, message = %s, result = %s" 58 | .format(topic, message, result.toString())) 59 | case Failure(ex) => logger.error( 60 | "AWS-SNS :: failed to publish a message. topic = %s, message = %s" 61 | .format(topic, message), ex) 62 | } 63 | } 64 | } 65 | } yield resultSeq 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/mvc/QueryStringHelper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.mvc 10 | 11 | import play.api.mvc.Results.BadRequest 12 | import play.api.mvc.{ QueryStringBindable, Result } 13 | import scala.language.implicitConversions 14 | 15 | /** 16 | * Extending `QueryStringBindable` 17 | */ 18 | trait QueryStringHelper extends binder.Box { 19 | 20 | implicit def toQueryStringHelperOps[A](bindable: QueryStringBindable[A]) = 21 | QueryStringHelper.QueryStringHelperOps(bindable) 22 | 23 | implicit def toQueryStringHelperBoxCsvOps[A](bindable: QueryStringBindable[BoxCsv[A]]) = 24 | QueryStringHelper.QueryStringHelperBoxCsvOps(bindable) 25 | } 26 | 27 | /** 28 | * Companion object 29 | */ 30 | object QueryStringHelper extends binder.Box { 31 | 32 | /** 33 | * Operations extending `QueryStringBindable` 34 | */ 35 | case class QueryStringHelperOps[A](val bindable: QueryStringBindable[A]) extends AnyVal { 36 | 37 | /** 38 | * Get a value from queryString parameter. 39 | */ 40 | def bindOption(key: String) 41 | (implicit params: Map[String, Seq[String]]): Either[Result, Option[A]] = 42 | _bindOption(key).left.map(BadRequest(_)) 43 | 44 | /** 45 | * Get a value from queryString parameter. 46 | */ 47 | private[mvc] def _bindOption(key: String) 48 | (implicit params: Map[String, Seq[String]]): Either[String, Option[A]] = 49 | bindable.bind(key, params) match { 50 | case None => Right(None) 51 | case Some(Right(v)) => Right(Some(v)) 52 | case Some(Left(v)) => Left(v) 53 | } 54 | } 55 | 56 | /** 57 | * Operations extending `QueryStringBindable` 58 | */ 59 | case class QueryStringHelperBoxCsvOps[A](val bindable: QueryStringBindable[BoxCsv[A]]) extends AnyVal { 60 | 61 | /** 62 | * Get a value from queryString parameter. 63 | */ 64 | def bind(key: String) 65 | (implicit params: Map[String, Seq[String]]): Either[Result, Seq[A]] = 66 | _bind(key).left.map(BadRequest(_)) 67 | 68 | /** 69 | * Get a value from queryString parameter. 70 | */ 71 | private[mvc] def _bind(key: String) 72 | (implicit params: Map[String, Seq[String]]): Either[String, Seq[A]] = 73 | bindable.bind(key, params) match { 74 | case None => Right(Nil) 75 | case Some(Right(v)) => Right(v()) 76 | case Some(Left(v)) => Left(v) 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/action/SlickDBAction.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.action 10 | 11 | import scala.util.Failure 12 | import scala.concurrent.Future 13 | import slick.jdbc.JdbcProfile 14 | import slick.dbio.{ DBIOAction, NoStream } 15 | import ixias.persistence.SlickProfile 16 | import ixias.persistence.model.{ DataSourceName, Table } 17 | 18 | trait SlickDBActionProvider[P <: JdbcProfile] { self: SlickProfile[P] => 19 | 20 | /** The default using key of DSN map. */ 21 | val DEFAULT_DSN_KEY = DataSourceName.RESERVED_NAME_MASTER 22 | 23 | /** 24 | * The Request of Invocation. 25 | */ 26 | sealed case class SlickDBActionRequest[T <: Table[_, P]]( 27 | val dsn: DataSourceName, 28 | val table: T 29 | ) 30 | 31 | sealed case class SlickDBAction[T <: Table[_, P]]() 32 | extends BasicAction[SlickDBActionRequest[T], (Database, T#Query)] 33 | { 34 | type Request = SlickDBActionRequest[T] 35 | type BlockArgument = (Database, T#Query) 36 | /** Run block process */ 37 | def invokeBlock[A](req: Request, block: BlockArgument => Future[A]): Future[A] = 38 | (for { 39 | db <- backend.getDatabase(req.dsn) 40 | value <- block((db, req.table.query)) 41 | } yield value) andThen { 42 | case Failure(ex) => logger.error( 43 | "The database action failed. dsn=%s".format(req.dsn.toString), ex) 44 | } 45 | } 46 | 47 | /** 48 | * The Database Acion 49 | */ 50 | object SlickDBAction extends SlickDBAction { 51 | 52 | /** Invoke DB action block. */ 53 | def apply[A, B, T <: Table[_, P]] 54 | (table: T, hostspec: String = DEFAULT_DSN_KEY) 55 | (block: ((Database, T#Query)) => Future[A]) 56 | (implicit conv: A => B): Future[B] = 57 | for { 58 | dsn <- Future(table.dsn.get(hostspec).get) 59 | value <- SlickDBAction[T].invokeBlock(SlickDBActionRequest(dsn, table), block) 60 | } yield conv(value) 61 | } 62 | 63 | /** 64 | * The Database Acion 65 | */ 66 | object SlickRunDBAction extends SlickDBAction { 67 | 68 | /** Invoke DB action block. */ 69 | def apply[A, B, T <: Table[_, P]] 70 | (table: T, hostspec: String = DEFAULT_DSN_KEY) 71 | (action: T#Query => DBIOAction[A, NoStream, Nothing]) 72 | (implicit conv: A => B): Future[B] = 73 | for { 74 | dsn <- Future(table.dsn.get(hostspec).get) 75 | value <- SlickDBAction[T].invokeBlock(SlickDBActionRequest(dsn, table), { 76 | case (db, slick) => db.run(action(slick)) 77 | }) 78 | } yield conv(value) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/model/TableQuery.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.model 10 | 11 | import ixias.model._ 12 | 13 | /** 14 | * Definition to execute a query from the target table 15 | */ 16 | abstract class TableQuery[K <: Document.Id[_], M <: EntityModel[K]] 17 | (val tableName: String)(implicit ctag: reflect.ClassTag[M]) extends ConvOps { 18 | 19 | // -- [ Basic queries ] --------------------------------- 20 | lazy val get = (id: M#Id) => 21 | sql("SELECT id, t.* FROM __TABLE_NAME__ AS t BY id WHERE id = ?", id) 22 | .result[M].headOption 23 | 24 | lazy val add = (data: M#WithNoId) => 25 | sql("INSERT INTO __TABLE_NAME__ VALUE ?", data.v) 26 | .affectedDocs.headOption 27 | 28 | lazy val delete = (id: M#Id) => 29 | sql("DELETE FROM __TABLE_NAME__ BY id WHERE id = ?", id) 30 | .affectedDocs.headOption 31 | 32 | lazy val update = (data: M#EmbeddedId) => 33 | sql("UPDATE __TABLE_NAME__ AS t BY id SET t = ? WHERE t != ? AND id = ?", data.v, data.v, data.id) 34 | .affectedDocs.headOption 35 | 36 | // -- [ Methods to create statement object ] --------------------------------- 37 | def sql 38 | (stmt: String) 39 | = SqlPrepareStatement(tableName, stmt, Seq.empty) 40 | def sql[P1] 41 | (stmt: String, p1: P1) 42 | = SqlPrepareStatement(tableName, stmt, Seq(p1)) 43 | def sql[P1, P2] 44 | (stmt: String, p1: P1, p2: P2) 45 | = SqlPrepareStatement(tableName, stmt, Seq(p1, p2)) 46 | def sql[P1, P2, P3] 47 | (stmt: String, p1: P1, p2: P2, p3: P3) 48 | = SqlPrepareStatement(tableName, stmt, Seq(p1, p2, p3)) 49 | def sql[P1, P2, P3, P4] 50 | (stmt: String, p1: P1, p2: P2, p3: P3, p4: P4) 51 | = SqlPrepareStatement(tableName, stmt, Seq(p1, p2, p3, p4)) 52 | def sql[P1, P2, P3, P4, P5] 53 | (stmt: String, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) 54 | = SqlPrepareStatement(tableName, stmt, Seq(p1, p2, p3, p4, p5)) 55 | def sql[P1, P2, P3, P4, P5, P6] 56 | (stmt: String, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) 57 | = SqlPrepareStatement(tableName, stmt, Seq(p1, p2, p3, p4, p5, p6)) 58 | def sql[P1, P2, P3, P4, P5, P6, P7] 59 | (stmt: String, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) 60 | = SqlPrepareStatement(tableName, stmt, Seq(p1, p2, p3, p4, p5, p6, p7)) 61 | def sql[P1, P2, P3, P4, P5, P6, P7, P8] 62 | (stmt: String, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8) 63 | = SqlPrepareStatement(tableName, stmt, Seq(p1, p2, p3, p4, p5, p6, p7, p8)) 64 | def sql[P1, P2, P3, P4, P5, P6, P7, P8, P9] 65 | (stmt: String, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9) 66 | = SqlPrepareStatement(tableName, stmt, Seq(p1, p2, p3, p4, p5, p6, p7, p8, p9)) 67 | } 68 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/model/SqlStatement.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.model 10 | 11 | import scala.util.Try 12 | import collection.JavaConverters._ 13 | import com.amazon.ion.IonValue 14 | import software.amazon.qldb.{ QldbSession, TransactionExecutor } 15 | 16 | /** 17 | * Sql prepare statement 18 | */ 19 | trait SqlStatement { 20 | 21 | type Result = ResultContainer#Result 22 | type ResultContainer <: SqlResultContainer 23 | 24 | val query: String 25 | val params: Seq[IonValue] 26 | 27 | /** 28 | * Store in container 29 | */ 30 | def toResult(data: software.amazon.qldb.Result): ResultContainer 31 | 32 | /** 33 | * Execute query 34 | */ 35 | def execute(session: QldbSession): Try[Result] = 36 | Try { 37 | toResult(session.execute(query, params.asJava)).value 38 | } 39 | 40 | /** 41 | * Execute query with transaction 42 | */ 43 | def execute(tx: TransactionExecutor): Try[Result] = 44 | Try { 45 | toResult(tx.execute(query, params.asJava)).value 46 | } 47 | } 48 | 49 | /** 50 | * Companion object 51 | */ 52 | object SqlStatement { 53 | 54 | /** 55 | * Design that returns a single record result with `Option` type 56 | */ 57 | case class ForSingleResult[M]( 58 | query: String, 59 | params: Seq[IonValue] 60 | )(implicit val ctag: reflect.ClassTag[M]) extends SqlStatement { 61 | 62 | /** 63 | * Store in container 64 | */ 65 | def toResult(data: software.amazon.qldb.Result): ResultContainer = 66 | ResultContainer(data) 67 | 68 | /** 69 | * Result container definition 70 | */ 71 | case class ResultContainer(data: software.amazon.qldb.Result) extends SqlResultContainer with ConvOps { 72 | type Model = M 73 | type Result = Option[Model] 74 | lazy val value = data.toModelSeq.headOption 75 | } 76 | } 77 | 78 | /** 79 | * Design that returns a single record result with `Seq` type 80 | */ 81 | case class ForMultiResult[M]( 82 | query: String, 83 | params: Seq[IonValue] 84 | )(implicit val ctag: reflect.ClassTag[M]) extends SqlStatement { 85 | 86 | /** 87 | * Set flags to get only a head of the result data 88 | */ 89 | def headOption = ForSingleResult(query, params) 90 | 91 | /** 92 | * Store in container 93 | */ 94 | def toResult(data: software.amazon.qldb.Result): ResultContainer = 95 | ResultContainer(data) 96 | 97 | /** 98 | * Result container definition 99 | */ 100 | case class ResultContainer(data: software.amazon.qldb.Result) extends SqlResultContainer with ConvOps { 101 | type Model = M 102 | type Result = Seq[Model] 103 | lazy val value = data.toModelSeq 104 | } 105 | } 106 | } 107 | 108 | -------------------------------------------------------------------------------- /framework/ixias-play-scalate/src/main/scala/ixias/play/api/scalate/mvc/JadeHelper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.scalate.mvc 10 | 11 | import play.twirl.api.Html 12 | import play.api.{ Environment, Configuration } 13 | 14 | import org.fusesource.scalate.{ TemplateEngine, InvalidSyntaxException } 15 | import org.fusesource.scalate.util.FileResourceLoader 16 | import org.fusesource.scalate.layout.DefaultLayoutStrategy 17 | 18 | // Jade 取り扱い処理 19 | //~~~~~~~~~~~~~~~~~~~~ 20 | object JadeHelper { 21 | 22 | // -- [ Properties ]---------------------------------------------------------- 23 | lazy val templateEngine = (env: Environment, conf: Configuration) => { 24 | val engine = new TemplateEngine 25 | engine.resourceLoader = new FileResourceLoader(getTemplateDir(env, conf)) 26 | engine.workingDirectory = env.getFile("target/jade") 27 | engine.classpath = engine.workingDirectory.toString + "/classes" 28 | engine.combinedClassPath = true 29 | engine.classLoader = env.classLoader 30 | engine.importStatements ++= getImportStatements(conf) 31 | engine 32 | } 33 | 34 | // -- [ Methods ]------------------------------------------------------------- 35 | /** 36 | * Build a template component to render HTML. 37 | */ 38 | def apply(template: String, layout: Option[String] = None) = Template(template, layout) 39 | 40 | /** 41 | * The root directory for template. 42 | */ 43 | def getTemplateDir(env: Environment, conf: Configuration): Option[java.io.File] = 44 | conf.get[Option[String]]("jade.template.path") match { 45 | case Some(path) => Some(env.getFile(path)) 46 | case _ => Some(env.getFile("app/views")) 47 | } 48 | 49 | /** 50 | * The declaration for `import` statement in template. 51 | */ 52 | def getImportStatements(conf: Configuration): Seq[String] = 53 | conf.get[Seq[String]]("jade.import") 54 | 55 | // -- [ Internal class ]------------------------------------------------------ 56 | /** 57 | * The definition of template component. 58 | */ 59 | sealed case class Template(template: String, layout: Option[String]) { 60 | /** 61 | * Renders a HTML body-text with parameters. 62 | */ 63 | def render(params: Map[String, Any] = Map.empty)(implicit env: Environment, conf: Configuration): Html = { 64 | val engine = templateEngine(env, conf) 65 | try { 66 | if (layout.isDefined) 67 | engine.layoutStrategy = new DefaultLayoutStrategy(engine, layout.get) 68 | Html(engine.layout(template, params)) 69 | } catch { 70 | case ex: InvalidSyntaxException => throw new JadeCompilationException( 71 | ex.brief, 72 | engine.resourceLoader.load(ex.template), 73 | ex.pos.line, 74 | ex.pos.column, 75 | ex.brief, 76 | ex 77 | ) 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/mvc/binder/JavaTime.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.mvc.binder 10 | 11 | import java.time.{ LocalDate, YearMonth } 12 | import play.api.mvc.QueryStringBindable 13 | 14 | trait JavaTimeBindable { 15 | 16 | // --[ Typedefs ]------------------------------------------------------------- 17 | type LocalDate = java.time.LocalDate 18 | type LocalDateRange = (java.time.LocalDate, java.time.LocalDate) 19 | type YearMonth = java.time.YearMonth 20 | type YearMonthRange = (java.time.YearMonth, java.time.YearMonth) 21 | 22 | // -- [ LocalDate ] ---------------------------------------------------------- 23 | /** 24 | * QueryString binder for LocalDate 25 | */ 26 | implicit object queryStringBindableLocalDate extends QueryStringBindable.Parsing[LocalDate]( 27 | (s: String) => LocalDate.parse(s), 28 | (date: LocalDate) => date.toString, 29 | (key: String, e: Exception) => { 30 | "Cannot parse parameter %s as LocalDate: %s" 31 | .format(key, e.getMessage) 32 | } 33 | ) 34 | 35 | /** 36 | * QueryString binder for LocalDate -> LocalDate 37 | */ 38 | implicit object queryStringBindableLocalDateRange extends QueryStringBindable.Parsing[LocalDateRange]( 39 | (s: String) => s.split(",").map(LocalDate.parse).toSeq match { 40 | case Seq(v1, v2) => (v1, v2) 41 | case _ => throw new IllegalArgumentException("The date-range value syntax is not valid") 42 | }, 43 | (r: LocalDateRange) => Seq(r._1.toString, r._2.toString).mkString(","), 44 | (key: String, e: Exception) => { 45 | "Cannot parse parameter %s as LocalDateRange: %s" 46 | .format(key, e.getMessage) 47 | } 48 | ) 49 | 50 | // -- [ YearMonth ] ---------------------------------------------------------- 51 | /** 52 | * QueryString binder for YearMonth 53 | */ 54 | implicit object queryStringBindableYearMonth extends QueryStringBindable.Parsing[YearMonth]( 55 | (s: String) => YearMonth.parse(s), 56 | (ymonth: YearMonth) => ymonth.toString, 57 | (key: String, e: Exception) => { 58 | "Cannot parse parameter %s as YearMonth: %s" 59 | .format(key, e.getMessage) 60 | } 61 | ) 62 | 63 | /** 64 | * QueryString binder for YearMonth -> YearMonth 65 | */ 66 | implicit object queryStringBindableYearMonthRange extends QueryStringBindable.Parsing[YearMonthRange]( 67 | (s: String) => s.split(",").map(YearMonth.parse).toSeq match { 68 | case Seq(v1, v2) => (v1, v2) 69 | case _ => throw new IllegalArgumentException("The date-range value syntax is not valid") 70 | }, 71 | (r: YearMonthRange) => Seq(r._1.toString, r._2.toString).mkString(","), 72 | (key: String, e: Exception) => { 73 | "Cannot parse parameter %s as YearMonthRange: %s" 74 | .format(key, e.getMessage) 75 | } 76 | ) 77 | } 78 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/backend/SlickConfig.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.backend 10 | 11 | import scala.util.Try 12 | import scala.concurrent.duration.Duration 13 | import ixias.persistence.model.DataSourceName 14 | 15 | trait SlickConfig extends BasicDatabaseConfig { 16 | 17 | // --[ Properties ]----------------------------------------------------------- 18 | /** The keys of configuration */ 19 | protected val CF_HOSTSPEC_MIN_IDLE = "min_idle" 20 | protected val CF_HOSTSPEC_MAX_POOL_SIZE = "max_pool_size" 21 | protected val CF_HOSTSPEC_CONNECTION_TIMEOUT = "connection_timeout" 22 | protected val CF_HOSTSPEC_IDLE_TIMEOUT = "idle_timeout" 23 | 24 | // --[ Methods ]-------------------------------------------------------------- 25 | /** 26 | * Get the property controls the minimum number of idle connections that 27 | * Driver tries to maintain in the pool, including both idle and in-use connections. 28 | */ 29 | protected def getHostSpecMinIdle(implicit dsn: DataSourceName): Option[Int] = 30 | readValue(_.get[Option[Int]](CF_HOSTSPEC_MIN_IDLE)) 31 | 32 | /** 33 | * Get the property controls the maximum size that the pool is allowed to reach, 34 | * including both idle and in-use connections. Basically this value will determine 35 | * the maximum number of actual connections to the database backend. 36 | */ 37 | protected def getHostSpecMaxPoolSize(implicit dsn: DataSourceName): Option[Int] = 38 | readValue(_.get[Option[Int]](CF_HOSTSPEC_MAX_POOL_SIZE)) 39 | 40 | /** 41 | * Get the maximum number of milliseconds that a client will wait for 42 | * a connection from the pool. If this time is exceeded without 43 | * a connection becoming available, a SQLException will be thrown from 44 | */ 45 | protected def getHostSpecConnectionTimeout(implicit dsn: DataSourceName): Option[Long] = 46 | readValue(_.get[Option[Duration]](CF_HOSTSPEC_CONNECTION_TIMEOUT).map(_.toMillis)) 47 | 48 | /** 49 | * This property controls the maximum amount of time (in milliseconds) that 50 | * a connection is allowed to sit idle in the pool. 51 | * Whether a connection is retired as idle or not is subject to 52 | * a maximum variation of +30 seconds, and average variation of +15 seconds. 53 | * A connection will never be retired as idle before this timeout. 54 | * A value of 0 means that idle connections are never removed from the pool. 55 | */ 56 | protected def getHostSpecIdleTimeout(implicit dsn: DataSourceName): Option[Long] = 57 | readValue(_.get[Option[Duration]](CF_HOSTSPEC_IDLE_TIMEOUT).map(_.toMillis)) 58 | 59 | /** 60 | * Get the JDBC Url 61 | */ 62 | protected def getJdbcUrl(implicit dsn: DataSourceName): Try[String] = 63 | for { 64 | driver <- getDriverClassName 65 | builder <- SlickJdbcUrlBuilderProvider.resolve(driver) 66 | jdbcUrl <- builder.buildUrl 67 | } yield jdbcUrl 68 | } 69 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/dbio/EntityIOAction.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.dbio 10 | 11 | import scala.concurrent.Future 12 | import ixias.model.{ @@, Entity, EntityModel, IdStatus } 13 | import ixias.persistence.Repository 14 | 15 | /** 16 | * An Entity Action that can be executed on a persistence database. 17 | */ 18 | trait EntityIOAction[K <: @@[_, _], M <: EntityModel[K]] 19 | extends IOAction { self: Repository[K, M] => 20 | 21 | /** The type of entity id */ 22 | type Id = K 23 | 24 | /** The type of entity when it has not id. */ 25 | type EntityWithNoId = Entity[K, M, IdStatus.Empty] 26 | 27 | /** The type of entity when it has embedded id */ 28 | type EntityEmbeddedId = Entity[K, M, IdStatus.Exists] 29 | 30 | // --[ Methods ]-------------------------------------------------------------- 31 | /** 32 | * Defines the default value computation for the map, 33 | * returned when a identity is not found The method implemented here throws an exception, 34 | * but it might be overridden in subclasses. 35 | */ 36 | def default(id: Id): Future[EntityEmbeddedId] = 37 | Future.failed(new NoSuchElementException("identity not found: " + id)) 38 | 39 | /** 40 | * Retrieves the value which is associated with the given identity. 41 | * This method invokes the `default` method of the map if there is no mapping 42 | * from the given identity to a value. 43 | */ 44 | def apply(id: Id): Future[EntityEmbeddedId] = 45 | get(id).flatMap(_ match { 46 | case Some(v) => Future.successful(v) 47 | case None => default(id) 48 | }) 49 | 50 | // --[ Methods ]-------------------------------------------------------------- 51 | /** 52 | * Optionally returns the value associated with a identity. 53 | */ 54 | def get(id: Id): Future[Option[EntityEmbeddedId]] 55 | 56 | /** 57 | * Returns the value associated with a identity, or 58 | * a default value if the identity is not contained in the repository. 59 | */ 60 | def getOrElse[E2 >: EntityEmbeddedId](id: Id, f: Id => E2): Future[E2] = 61 | get(id).map(_.getOrElse(f(id))) 62 | 63 | /** 64 | * Tests whether this repository contains a binding for a identity. 65 | */ 66 | def contains(id: Id): Future[Boolean] = 67 | get(id).map(_.isDefined) 68 | 69 | // --[ Methods ]-------------------------------------------------------------- 70 | /** 71 | * Adds a new identity/entity-value pair to this repository. 72 | */ 73 | def add(entity: EntityWithNoId): Future[Id] 74 | 75 | /** 76 | * If the dataset already contains a mapping for the identity, 77 | * it will be overridden by the new value. 78 | */ 79 | def update(entity: EntityEmbeddedId): Future[Option[EntityEmbeddedId]] 80 | 81 | /** 82 | * Removes a identity from this map, 83 | * returning the value associated previously with that identity as an option. 84 | */ 85 | def remove(id: Id): Future[Option[EntityEmbeddedId]] 86 | } 87 | -------------------------------------------------------------------------------- /framework/ixias-mail/src/main/scala/ixias/EmailTemplate.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.mail 10 | 11 | import java.io.File 12 | 13 | // User's email data 14 | //~~~~~~~~~~~~~~~~~~~~ 15 | case class UserEmail( 16 | val address: String, // E-mail address, of phone number (SMS) 17 | val firstName: Option[String] = None, // The user's first name 18 | val lastName: Option[String] = None, // The user's last name 19 | val isSetName: Boolean = false // The flag to indicate whether the E-mail address should be include personal name. 20 | ) { 21 | def name = Option(Seq(lastName, firstName).collect({ case Some(v) => v }).mkString(" ")) 22 | } 23 | 24 | // Email's Attachment 25 | //~~~~~~~~~~~~~~~~~~~~ 26 | sealed trait Attachment 27 | 28 | case class AttachmentFile( 29 | val name: String, 30 | val file: File, 31 | val description: Option[String] = None, 32 | val disposition: Option[String] = None 33 | ) extends Attachment 34 | 35 | case class AttachmentData( 36 | val name: String, 37 | val data: Array[Byte], 38 | val mimetype: String, 39 | val description: Option[String] = None, 40 | val disposition: Option[String] = None 41 | ) extends Attachment 42 | 43 | trait EmailTemplate[P] extends EmailConfig { 44 | 45 | /** The E-mail's subject */ 46 | val subject: String 47 | 48 | /** The sender data */ 49 | val from: Option[UserEmail] = None 50 | 51 | /** Add recipients CC to the email using the specified address */ 52 | val cc: Seq[UserEmail] = Seq.empty 53 | 54 | /** Add recipients BCC to the email using the specified address */ 55 | val bcc: Seq[UserEmail] = Seq.empty 56 | 57 | /** The Email's headers */ 58 | val headers: Seq[(String, String)] = Seq.empty 59 | 60 | /** The Email's attachment files */ 61 | val attachments: Seq[Attachment] = Seq.empty 62 | 63 | /** The Email's provided parameters */ 64 | val params: P 65 | 66 | /** The flag to indicate whether email-client ignore errors */ 67 | val silent: Boolean = false 68 | 69 | // --[ Properties ]----------------------------------------------------------- 70 | /** The charset */ 71 | lazy val charset: String = getCharset() 72 | 73 | /** The bounce address */ 74 | lazy val bounceAddress: Option[String] = getBounceAddress() 75 | 76 | // --[ Methods ]----------------------------------------------------------- 77 | /** 78 | * Build a E-mail's body (PlainText) with using provided data. 79 | */ 80 | def getBodyText(to: UserEmail, from: UserEmail): Option[String] = None 81 | 82 | /** 83 | * Build a E-mail's body (HTML) with using provided data. 84 | */ 85 | def getBodyHtml(to: UserEmail, from: UserEmail): Option[String] = None 86 | 87 | /** 88 | * Build a SMS's short message body (PlainText) with using provided data. 89 | */ 90 | def getBodySMSText(to: UserEmail, from: UserEmail): Option[String] = None 91 | } 92 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/backend/SlickBackend.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.backend 10 | 11 | import java.sql.Connection 12 | import scala.concurrent.Future 13 | import scala.util.{ Success, Failure } 14 | 15 | import com.zaxxer.hikari.{ HikariConfig, HikariDataSource } 16 | import slick.jdbc.{ JdbcProfile, JdbcBackend, JdbcDataSource } 17 | import ixias.persistence.model.DataSourceName 18 | 19 | /** 20 | * The slick backend to handle the database and session. 21 | */ 22 | case class SlickBackend[P <: JdbcProfile](val driver: P) 23 | extends BasicBackend[P#Backend#Database] with SlickConfig { 24 | 25 | /** Get a Database instance from connection pool. */ 26 | def getDatabase(implicit dsn: DataSourceName): Future[Database] = 27 | SlickDatabaseContainer.getOrElseUpdate { 28 | (for { 29 | ds <- createDataSource 30 | db <- Future(driver.backend.Database.forSource(ds)) 31 | } yield db) andThen { 32 | case Success(_) => logger.info("Created a new data souce. dsn=%s".format(dsn.toString)) 33 | case Failure(_) => logger.info("Failed to create a data souce. dsn=%s".format(dsn.toString)) 34 | } 35 | } 36 | 37 | /** Create a JdbcDataSource from DSN (Database Souce Name) */ 38 | def createDataSource(implicit dsn: DataSourceName): Future[HikariCPDataSource] = 39 | Future.fromTry { 40 | for { 41 | driver <- getDriverClassName 42 | url <- getJdbcUrl 43 | } yield { 44 | val hconf = new HikariConfig() 45 | hconf.setDriverClassName(driver) 46 | hconf.setJdbcUrl(url) 47 | hconf.setPoolName(dsn.toString) 48 | hconf.addDataSourceProperty("useSSL", false) 49 | 50 | // Optional properties. 51 | getUserName map hconf.setUsername 52 | getPassword map hconf.setPassword 53 | getHostSpecReadOnly map hconf.setReadOnly 54 | getHostSpecMinIdle map hconf.setMinimumIdle 55 | getHostSpecMaxPoolSize map hconf.setMaximumPoolSize 56 | getHostSpecConnectionTimeout map hconf.setConnectionTimeout 57 | getHostSpecIdleTimeout map hconf.setIdleTimeout 58 | HikariCPDataSource(new HikariDataSource(hconf), hconf) 59 | } 60 | } 61 | 62 | /** The DataSource */ 63 | sealed case class HikariCPDataSource ( 64 | val ds: HikariDataSource, 65 | val hconf: HikariConfig 66 | ) extends JdbcDataSource { 67 | 68 | /** The maximum pool size. */ 69 | val maxConnections: Option[Int] = None 70 | 71 | /** Create a new Connection or get one from the pool */ 72 | def createConnection(): Connection = ds.getConnection() 73 | 74 | /** 75 | * If this object represents a connection pool managed directly by Slick, close it. 76 | * Otherwise no action is taken. 77 | */ 78 | def close(): Unit = ds.close() 79 | } 80 | } 81 | 82 | /** Manage data sources associated with DSN */ 83 | object SlickDatabaseContainer extends BasicDatabaseContainer[JdbcBackend#Database] 84 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/controllers/UIAssets.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.controllers 10 | 11 | import akka.util.ByteString 12 | import akka.stream.scaladsl.Source 13 | import scala.concurrent.ExecutionContext 14 | 15 | import play.api.{ Mode, Environment, Configuration } 16 | import play.api.http.{ HttpEntity, FileMimeTypes, HttpErrorHandler } 17 | import play.api.mvc.{ Action, AnyContent } 18 | import play.api.libs.iteratee.Enumerator 19 | import play.api.libs.iteratee.streams.IterateeStreams 20 | import play.api.Logger 21 | 22 | import controllers.{ AssetsBuilder, DefaultAssetsMetadata } 23 | 24 | @javax.inject.Singleton 25 | class UIAssets @javax.inject.Inject() ( 26 | env: Environment, 27 | conf: Configuration, 28 | errorHandler: HttpErrorHandler, 29 | meta: DefaultAssetsMetadata, 30 | fileMimeTypes: FileMimeTypes 31 | )(implicit ec: ExecutionContext) extends AssetsBuilder(errorHandler, meta) { 32 | 33 | import controllers.Assets._ 34 | 35 | protected val CF_ASSETS_DEV_DIR = "assets.dev.dirs" 36 | 37 | /** The logger */ 38 | private lazy val logger = Logger(getClass) 39 | 40 | /** Assets Handler */ 41 | override def versioned(path: String, file: Asset): Action[AnyContent] = { 42 | env.mode match { 43 | case Mode.Prod => super.versioned(path, file) 44 | case _ => devAssetHandler(file.name) 45 | } 46 | } 47 | 48 | /** 開発モード時にAssetsを提供するディレクトリ・リスト */ 49 | val basePaths: Seq[java.io.File] = 50 | conf.getOptional[Seq[String]](CF_ASSETS_DEV_DIR) match { 51 | case Some(dirs) => dirs.map(env.getFile).filter(_.exists) 52 | case None => Seq( 53 | env.getFile("ui"), 54 | env.getFile("ui/src"), 55 | env.getFile("ui/build"), 56 | env.getFile("ui/dist"), 57 | env.getFile("target/web/public/main") 58 | ).filter(_.exists) 59 | } 60 | 61 | /** Assetsハンドラー : 開発モード */ 62 | private def devAssetHandler(file: String): Action[AnyContent] = Action { implicit request => 63 | val resource = basePaths.foldLeft[Option[java.io.File]](None) { 64 | case (prev, path) => prev match { 65 | case Some(_) => prev 66 | case None => { 67 | val fullPath = path + "/" + file 68 | val resource = new java.io.File(fullPath) 69 | if (resource.isFile) Some(resource) else None 70 | } 71 | } 72 | } 73 | resource match { 74 | case Some(file) => { 75 | val data = Enumerator.fromStream(new java.io.FileInputStream(file)) 76 | val source = Source.fromPublisher(IterateeStreams.enumeratorToPublisher(data)).map(ByteString.apply) 77 | logger.info(s"serving $file") 78 | Ok.sendEntity(HttpEntity.Streamed(source, None, None)) 79 | .as(fileMimeTypes.forFileName(file.toString).getOrElse("application/octet-stream")) 80 | .withHeaders(CACHE_CONTROL -> "no-store") 81 | } 82 | case None => { 83 | NotFound("404 - Page not found error. path=" + request.path) 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/mvc/RequestHeaderAttrHelper.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.mvc 10 | 11 | import cats.data.{ Validated, ValidatedNel, NonEmptyList } 12 | import scala.reflect.runtime.universe._ 13 | import scala.language.implicitConversions 14 | 15 | import play.api.mvc.{ RequestHeader, Result } 16 | import play.api.libs.typedmap.TypedKey 17 | import ixias.util.Logging 18 | 19 | // Helper to get header attrs 20 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 21 | object RequestHeaderAttrHelper extends Logging { 22 | import Errors._ 23 | 24 | /** 25 | * Retrieves and validate a value of the specified key. 26 | */ 27 | def getValue[T](key: TypedKey[T])(implicit rh: RequestHeader, tag: TypeTag[T]): ValidatedNel[String, T] = 28 | rh.attrs.get(key) match { 29 | case Some(v) => Validated.Valid(v) 30 | case None => { 31 | Validated.Invalid(NonEmptyList.of( 32 | "The value under the specified key was not found. Entity type is " 33 | + tag.tpe.toString 34 | )) 35 | } 36 | } 37 | 38 | /** 39 | * Implicit convert. ValidatedNel to Either 40 | */ 41 | implicit def toEither[T](validated: ValidatedNel[String, T]): Either[Result, T] = 42 | validated match { 43 | case Validated.Valid(v) => Right(v) 44 | case Validated.Invalid(nel) => { 45 | nel.map(invalid => logger.error(invalid)) 46 | Left(E_NOT_FOUND) 47 | } 48 | } 49 | 50 | /** case Tuple1 */ 51 | def get[T1](a1: TypedKey[T1]) 52 | (implicit rh: RequestHeader, tag1: TypeTag[T1]): 53 | Either[Result, T1] = 54 | getValue(a1) 55 | 56 | 57 | /** case Tuple2 */ 58 | import cats.implicits._ 59 | def get[T1, T2](a1: TypedKey[T1], a2: TypedKey[T2]) 60 | (implicit rh: RequestHeader, tag1: TypeTag[T1], tag2: TypeTag[T2]): 61 | Either[Result, (T1, T2)] = 62 | (getValue(a1), getValue(a2)) 63 | .mapN((_, _)) 64 | 65 | /** case Tuple3 */ 66 | def get[T1, T2, T3](a1: TypedKey[T1], a2: TypedKey[T2], a3: TypedKey[T3]) 67 | (implicit rh: RequestHeader, tag1: TypeTag[T1], tag2: TypeTag[T2], tag3: TypeTag[T3]): 68 | Either[Result, (T1, T2, T3)] = 69 | (getValue(a1), getValue(a2), getValue(a3)) 70 | .mapN((_, _, _)) 71 | 72 | /** case Tuple4 */ 73 | def get[T1, T2, T3, T4](a1: TypedKey[T1], a2: TypedKey[T2], a3: TypedKey[T3], a4: TypedKey[T4]) 74 | (implicit rh: RequestHeader, tag1: TypeTag[T1], tag2: TypeTag[T2], tag3: TypeTag[T3], tag4: TypeTag[T4]): 75 | Either[Result, (T1, T2, T3, T4)] = 76 | (getValue(a1), getValue(a2), getValue(a3), getValue(a4)) 77 | .mapN((_, _, _, _)) 78 | 79 | /** case Tuple5 */ 80 | def get[T1, T2, T3, T4, T5](a1: TypedKey[T1], a2: TypedKey[T2], a3: TypedKey[T3], a4: TypedKey[T4], a5: TypedKey[T5]) 81 | (implicit rh: RequestHeader, tag1: TypeTag[T1], tag2: TypeTag[T2], tag3: TypeTag[T3], tag4: TypeTag[T4], tag5: TypeTag[T5]): 82 | Either[Result, (T1, T2, T3, T4, T5)] = 83 | (getValue(a1), getValue(a2), getValue(a3), getValue(a4), getValue(a5)) 84 | .mapN((_, _, _, _, _)) 85 | } 86 | -------------------------------------------------------------------------------- /framework/ixias-aws-s3/src/main/scala/ixias/aws/s3/model/FileBuilder.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.s3.model 10 | 11 | import ixias.model._ 12 | import ixias.security.RandomStringToken 13 | import ixias.aws.s3.backend.DataSourceName 14 | 15 | // To build file a object 16 | //~~~~~~~~~~~~~~~~~~~~~~~~~ 17 | trait FileBuilder[S <: @@[_, _], M <: AnyRef] { self => 18 | 19 | type SiloBaseId = S 20 | type SiloBase = FileSilo[S] 21 | type Model = M 22 | 23 | // --[ Properties ]----------------------------------------------------------- 24 | /** Silo configuration */ 25 | val siloBase: SiloBase 26 | 27 | /** Feature name */ 28 | val fileNamespace: String 29 | 30 | /** Prefix of filename */ 31 | val filePrefix: String 32 | 33 | /** directory seperator as string */ 34 | val DIRECTORY_SEPARATOR = """/""" 35 | 36 | // --[ Methods ]------------------------------------------------------------ 37 | /** 38 | * Get a base-id for silo generation. 39 | */ 40 | protected def siloBaseId(base: Model): SiloBaseId 41 | 42 | /** 43 | * Get a key-name of the file in the storage destination. 44 | */ 45 | protected def build(namespace: String, fname: String, base: Model): String = ( 46 | namespace 47 | :: siloBase.silo(self.siloBaseId(base)) 48 | :: fname 49 | :: Nil 50 | ).mkString(DIRECTORY_SEPARATOR) 51 | 52 | // --[ Methods ]------------------------------------------------------------ 53 | /** 54 | * Get a key-name of the file in the storage destination. 55 | */ 56 | final def apply(base: Model, typedef: String = "unknown") 57 | (implicit dsn: DataSourceName): File#WithNoId = 58 | (for { 59 | fkey <- scala.util.Try(build( 60 | fileNamespace, 61 | "%s-%s".format(filePrefix, RandomStringToken.next(64)), 62 | base 63 | )) 64 | file <- File(fkey, typedef, None) 65 | } yield file) getOrElse { 66 | val message = "Failed to create file object. dsn, baseModel = %s".format(dsn, base) 67 | throw new IllegalStateException(message) 68 | } 69 | } 70 | 71 | // To build file a object 72 | //~~~~~~~~~~~~~~~~~~~~~~~~~ 73 | trait FileBuilderExt[S1 <: @@[_, _], S2 <: @@[_, _], M <: AnyRef] extends FileBuilder[S2, M] { self => 74 | 75 | type SiloRootId = S1 76 | type SiloRoot = FileSilo[S1] 77 | 78 | // --[ Properties ]----------------------------------------------------------- 79 | /** Silo configuration */ 80 | val siloRoot: SiloRoot 81 | 82 | // --[ Methods ]------------------------------------------------------------ 83 | /** 84 | * Get a root-id for silo generation. 85 | */ 86 | protected def siloRootId(root: Model): SiloRootId 87 | 88 | /** 89 | * Get a key-name of the file in the storage destination. 90 | */ 91 | override protected def build(namespace: String, fname: String, base: Model): String = ( 92 | siloRoot.silo(self.siloRootId(base)) 93 | :: namespace 94 | :: siloBase.silo(self.siloBaseId(base)) 95 | :: fname 96 | :: Nil 97 | ).mkString(DIRECTORY_SEPARATOR) 98 | 99 | } 100 | -------------------------------------------------------------------------------- /framework/ixias-aws-s3/src/main/scala/ixias/aws/s3/persistence/File.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.s3.persistence 10 | 11 | import java.time.LocalDateTime 12 | import slick.jdbc.JdbcProfile 13 | import ixias.aws.s3.model.File 14 | import ixias.aws.s3.backend.{ DataSourceName => S3DSN, AmazonS3Config } 15 | import ixias.persistence.model.Table 16 | 17 | // Table definition. 18 | //~~~~~~~~~~~~~~~~~~~~ 19 | case class FileTable[P <: JdbcProfile]()(implicit val driver: P, val s3dsn: S3DSN) 20 | extends Table[File, P] with AmazonS3Config { self => 21 | import apiUnsafe._ 22 | 23 | // --[ DNS ] ----------------------------------------------------------------- 24 | lazy val dsn = Map( 25 | "master" -> DataSourceName("ixias.db.mysql://master/" + s3dsn.resource), 26 | "slave" -> DataSourceName("ixias.db.mysql://slave/" + s3dsn.resource) 27 | ) 28 | 29 | // --[ Query ] --------------------------------------------------------------- 30 | class Query extends BasicQuery(new Table(_)) { 31 | def unique(fid: File.Id) = 32 | this.filter(_.id === fid) 33 | } 34 | lazy val query = new Query 35 | 36 | // --[ Table definition ] ---------------------------------------------------- 37 | class Table(tag: Tag) extends BasicTable(tag, getMetaTableName) { 38 | 39 | // Columns 40 | /* @1 */ def id = column[Option[Long]] ("id", O.UInt64, O.PrimaryKey, O.AutoInc) 41 | /* @2 */ def region = column[String] ("region", O.Utf8Char32) 42 | /* @3 */ def bucket = column[String] ("bucket", O.Utf8Char32) 43 | /* @4 */ def key = column[String] ("key", O.Utf8Char255) 44 | /* @5 */ def typedef = column[String] ("typedef", O.Utf8Char32) 45 | /* @6 */ def width = column[Option[Int]] ("width", O.UInt16) 46 | /* @7 */ def height = column[Option[Int]] ("height", O.UInt16) 47 | /* @8 */ def updatedAt = column[LocalDateTime] ("updated_at", O.TsCurrent) 48 | /* @9 */ def createdAt = column[LocalDateTime] ("created_at", O.Ts) 49 | 50 | // Indexes 51 | def ukey01 = index("key01", (bucket, key, region), unique = true) 52 | 53 | // All columns as a tuple 54 | import File._ 55 | type TableElementTuple = ( 56 | Option[Long], String, String, String, String, 57 | Option[Int], Option[Int], LocalDateTime, LocalDateTime 58 | ) 59 | 60 | // The * projection of the table 61 | def * = (id, region, bucket, key, typedef, width, height, updatedAt, createdAt) <> ( 62 | /* The bidirectional mappings : Tuple(table) => Model */ 63 | (t: TableElementTuple) => { 64 | val imageSize = (t._6, t._7) match { 65 | case (Some(width), Some(height)) => Some(ImageSize(width, height)) 66 | case _ => None 67 | } 68 | File(Some(Id(t._1.get)), t._2, t._3, t._4, t._5, imageSize, None, t._8, t._9) 69 | }, 70 | /* The bidirectional mappings : Model => Tuple(table) */ 71 | (v: TableElementType) => File.unapply(v).map { t => ( 72 | v.id, t._2, t._3, t._4, t._5, t._6.map(_.width), t._6.map(_.height), LocalDateTime.now(), t._9 73 | ) } 74 | ) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/backend/AmazonQLDBBackend.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.backend 10 | 11 | import scala.concurrent.Future 12 | import scala.collection.mutable.HashMap 13 | import scala.util.{ Try, Success, Failure } 14 | import ixias.persistence.model.DataSourceName 15 | import ixias.persistence.backend.BasicBackend 16 | 17 | import software.amazon.qldb.{ QldbSession, PooledQldbDriver } 18 | import com.amazonaws.auth.AWSStaticCredentialsProvider 19 | import com.amazonaws.services.qldbsession.AmazonQLDBSessionClientBuilder 20 | 21 | /** 22 | * The backend to get a client for AmazonQLDB 23 | */ 24 | object AmazonQLDBBackend extends BasicBackend[QldbSession] with AmazonQLDBConfig { 25 | 26 | val CACHE_DRIVER_MAP = new HashMap[DataSourceName, PooledQldbDriver]() 27 | val CACHE_SESSION_MAP = new HashMap[(Long, DataSourceName), QldbSession]() 28 | 29 | /** 30 | * Get a client to manage Amazon QLDB 31 | */ 32 | def getDatabase(implicit dsn: DataSourceName): Future[QldbSession] = { 33 | logger.debug("Get a database dsn=%s hash=%s".format(dsn.toString, dsn.hashCode)) 34 | Future.fromTry(getSession) 35 | } 36 | 37 | /** 38 | * Get a Amazon QLDB session 39 | */ 40 | def getSession(implicit dsn: DataSourceName): Try[QldbSession] = 41 | this.synchronized { 42 | val threadId = Thread.currentThread.getId 43 | CACHE_SESSION_MAP.get((threadId, dsn)) match { 44 | case Some(session) if !checkSessionIfClosed(session) => { 45 | Success(session) 46 | } 47 | case _ => { 48 | getDriver.map(driver => { 49 | val session = driver.getSession 50 | logger.info("Create a new session. dsn=%s".format(dsn.toString)) 51 | CACHE_SESSION_MAP.update((threadId, dsn), session) 52 | session 53 | }) 54 | } 55 | } 56 | } 57 | 58 | /** 59 | * Check if the session is closed 60 | * [NOTE] Useful only for session verification made with `PooledQldbDriver` 61 | */ 62 | def checkSessionIfClosed(session: QldbSession): Boolean = 63 | Try(session.getSessionToken) match { 64 | case Failure(_) => true 65 | case Success(_) => false 66 | } 67 | 68 | /** 69 | * Get a Amazon QLDB Driver to manage client session 70 | */ 71 | def getDriver(implicit dsn: DataSourceName): Try[PooledQldbDriver] = 72 | this.synchronized { 73 | CACHE_DRIVER_MAP.get(dsn) match { 74 | case Some(driver) => Success(driver) 75 | case None => for { 76 | credentials <- getAWSCredentials 77 | region <- getAWSRegion 78 | ledgerName <- getLedgerName 79 | } yield { 80 | val builder = AmazonQLDBSessionClientBuilder.standard 81 | .withCredentials(new AWSStaticCredentialsProvider(credentials)) 82 | .withRegion(region) 83 | val driver = PooledQldbDriver.builder 84 | .withLedger(ledgerName) 85 | .withRetryLimit(3) 86 | .withSessionClientBuilder(builder) 87 | .build 88 | logger.info("Create a new driver. dsn=%s".format(dsn.toString)) 89 | CACHE_DRIVER_MAP.update(dsn, driver) 90 | driver 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/dbio/Execution.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.dbio 10 | 11 | import java.util.ArrayDeque 12 | import scala.annotation.tailrec 13 | import scala.concurrent.{ ExecutionContextExecutor, ExecutionContext } 14 | 15 | /** 16 | * Contains the default ExecutionContext used by Iteratees. 17 | */ 18 | object Execution { 19 | 20 | def defaultExecutionContext: ExecutionContext = Implicits.defaultExecutionContext 21 | 22 | object Implicits { 23 | implicit def defaultExecutionContext: ExecutionContext = Execution.trampoline 24 | implicit def trampoline: ExecutionContextExecutor = Execution.trampoline 25 | } 26 | 27 | /** 28 | * Executes in the current thread. 29 | * Uses a thread local trampoline to make sure the stack doesn't overflow. 30 | */ 31 | object trampoline extends ExecutionContextExecutor { 32 | 33 | /* 34 | * A ThreadLocal value is used to 35 | * track the state of the trampoline in the current thread. 36 | */ 37 | private val local = new ThreadLocal[AnyRef] 38 | 39 | /** Marks an empty queue (see docs for `local`). */ 40 | private object Empty 41 | 42 | def execute(runnable: Runnable): Unit = { 43 | local.get match { 44 | case null => 45 | // Trampoline is inactive in this thread so start it up! 46 | try { 47 | local.set(Empty) 48 | runnable.run() 49 | executeScheduled() 50 | } finally { 51 | local.set(null) 52 | } 53 | case Empty => 54 | // Add this Runnable to our empty queue 55 | local.set(runnable) 56 | case next: Runnable => 57 | // Convert the single queued Runnable into an ArrayDeque 58 | // so we can schedule 2+ Runnables 59 | val runnables = new ArrayDeque[Runnable](4) 60 | runnables.addLast(next) 61 | runnables.addLast(runnable) 62 | local.set(runnables) 63 | case arrayDeque: ArrayDeque[_] => 64 | // Add this Runnable to the end of the existing ArrayDeque 65 | val runnables = arrayDeque.asInstanceOf[ArrayDeque[Runnable]] 66 | runnables.addLast(runnable) 67 | case illegal => 68 | throw new IllegalStateException( 69 | s"Unsupported trampoline ThreadLocal value: $illegal") 70 | } 71 | } 72 | 73 | /** 74 | * Run all tasks that have been scheduled in the ThreadLocal. 75 | */ 76 | @tailrec 77 | private def executeScheduled(): Unit = { 78 | local.get match { 79 | case Empty => 80 | // Nothing to run 81 | () 82 | case next: Runnable => 83 | // Mark the queue of Runnables after this one as empty 84 | local.set(Empty) 85 | next.run() 86 | executeScheduled() 87 | case arrayDeque: ArrayDeque[_] => 88 | val runnables = arrayDeque.asInstanceOf[ArrayDeque[Runnable]] 89 | // Rather than recursing, 90 | // we can use a more efficient while loop. 91 | while (!runnables.isEmpty) { 92 | val runnable = runnables.removeFirst() 93 | runnable.run() 94 | } 95 | case illegal => 96 | throw new IllegalStateException( 97 | s"Unsupported trampoline ThreadLocal value: $illegal") 98 | } 99 | } 100 | 101 | def reportFailure(t: Throwable): Unit = t.printStackTrace() 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/backend/BasicDatabaseConfig.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.backend 10 | 11 | import scala.util.Try 12 | import scala.collection.JavaConverters._ 13 | import ixias.util.Configuration 14 | import ixias.persistence.model.DataSourceName 15 | 16 | trait BasicDatabaseConfig { 17 | 18 | /** The section format */ 19 | protected val CF_SECTION_HOSTSPEC = """hostspec.%s""" 20 | 21 | /** The keys of configuration */ 22 | protected val CF_USERNAME = "username" 23 | protected val CF_PASSWORD = "password" 24 | protected val CF_DRIVER_CLASS_NAME = "driver_class_name" 25 | protected val CF_HOSTSPEC_HOSTS = "hosts" 26 | protected val CF_HOSTSPEC_DATABASE = "database" 27 | protected val CF_HOSTSPEC_SCHEMA = "schema" 28 | protected val CF_HOSTSPEC_READONLY = "readonly" 29 | 30 | /** The configuration */ 31 | protected val config = Configuration() 32 | 33 | // --[ Configuration ]-------------------------------------------------------- 34 | /** 35 | * Get a value by specified key. 36 | */ 37 | final protected def readValue[A](f: Configuration => Option[A])(implicit dsn: DataSourceName): Option[A] = 38 | Seq( 39 | dsn.path + "." + dsn.database + "." + CF_SECTION_HOSTSPEC.format(dsn.hostspec), 40 | dsn.path + "." + dsn.database, 41 | dsn.path + "." + CF_SECTION_HOSTSPEC.format(dsn.hostspec), 42 | dsn.path 43 | ).foldLeft[Option[A]](None) { 44 | case (prev, path) => prev.orElse { 45 | config.get[Option[Configuration]](path).flatMap(f(_)) 46 | } 47 | } 48 | 49 | // --[ Methods ]-------------------------------------------------------------- 50 | /** Get the username used for DataSource */ 51 | protected def getUserName(implicit dsn: DataSourceName): Option[String] = 52 | readValue(_.get[Option[String]](CF_USERNAME)) 53 | 54 | /** Get the password used for DataSource */ 55 | protected def getPassword(implicit dsn: DataSourceName): Option[String] = 56 | readValue(_.get[Option[String]](CF_PASSWORD)) 57 | 58 | /** Get the flag for connection in read-only mode. */ 59 | protected def getHostSpecReadOnly(implicit dsn: DataSourceName): Option[Boolean] = 60 | readValue(_.get[Option[Boolean]](CF_HOSTSPEC_READONLY)) 61 | 62 | // --[ Methods ]-------------------------------------------------------------- 63 | /** Get the JDBC driver class name. */ 64 | protected def getDriverClassName(implicit dsn: DataSourceName): Try[String] = 65 | Try(readValue(_.get[Option[String]](CF_DRIVER_CLASS_NAME)).get) 66 | 67 | /** Get the database name. */ 68 | protected def getDatabaseName(implicit dsn: DataSourceName): Try[String] = 69 | Try(readValue(_.get[Option[String]](CF_HOSTSPEC_DATABASE)).get) 70 | 71 | /** Get the schema name. */ 72 | protected def getSchemaName(implicit dsn: DataSourceName): Try[String] = 73 | Try(readValue(_.get[Option[String]](CF_HOSTSPEC_SCHEMA)).get) 74 | 75 | /** Get host list to connect to database. */ 76 | protected def getHosts(implicit dsn: DataSourceName): Try[Seq[String]] = { 77 | val path = dsn.path + '.' + dsn.database + '.' + CF_SECTION_HOSTSPEC.format(dsn.hostspec) 78 | val section = config.get[Configuration](path).underlying 79 | val opt = section.getAnyRef(CF_HOSTSPEC_HOSTS) match { 80 | case v: String => Seq(v) 81 | case v: java.util.List[_] => v.asScala.toList.map(_.toString) 82 | case _ => throw new Exception(s"""Illegal value type of host setting. { path: $dsn }""") 83 | } 84 | Try(opt) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/persistence/lifted/SlickColumnOptionOps.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.persistence.lifted 10 | 11 | import scala.language.implicitConversions 12 | import slick.sql.{ SqlTableComponent => STC } 13 | 14 | final case class SlickColumnOptionsExtension[T <: STC#ColumnOptions](self: T) { 15 | val Boolean = self.SqlType("BIT(1)") 16 | val Int8 = self.SqlType("TINYINT") 17 | val Int16 = self.SqlType("SMALLINT") 18 | val Int32 = self.SqlType("INT") 19 | val Int64 = self.SqlType("BIGINT") 20 | val UInt8 = self.SqlType("TINYINT UNSIGNED") 21 | val UInt16 = self.SqlType("SMALLINT UNSIGNED") 22 | val UInt32 = self.SqlType("INT UNSIGNED") 23 | val UInt64 = self.SqlType("BIGINT UNSIGNED") 24 | val AsciiChar8 = self.SqlType("VARCHAR(8) CHARACTER SET ascii") 25 | val AsciiChar16 = self.SqlType("VARCHAR(16) CHARACTER SET ascii") 26 | val AsciiChar32 = self.SqlType("VARCHAR(32) CHARACTER SET ascii") 27 | val AsciiChar64 = self.SqlType("VARCHAR(64) CHARACTER SET ascii") 28 | val AsciiChar128 = self.SqlType("VARCHAR(128) CHARACTER SET ascii") 29 | val AsciiChar255 = self.SqlType("VARCHAR(255) CHARACTER SET ascii") 30 | val AsciiCharBin8 = self.SqlType("VARCHAR(8) CHARACTER SET ascii COLLATE ascii_bin") 31 | val AsciiCharBin16 = self.SqlType("VARCHAR(16) CHARACTER SET ascii COLLATE ascii_bin") 32 | val AsciiCharBin32 = self.SqlType("VARCHAR(32) CHARACTER SET ascii COLLATE ascii_bin") 33 | val AsciiCharBin64 = self.SqlType("VARCHAR(64) CHARACTER SET ascii COLLATE ascii_bin") 34 | val AsciiCharBin128 = self.SqlType("VARCHAR(128) CHARACTER SET ascii COLLATE ascii_bin") 35 | val AsciiCharBin255 = self.SqlType("VARCHAR(255) CHARACTER SET ascii COLLATE ascii_bin") 36 | val Utf8Char8 = self.SqlType("VARCHAR(8) CHARACTER SET utf8mb4") 37 | val Utf8Char16 = self.SqlType("VARCHAR(16) CHARACTER SET utf8mb4") 38 | val Utf8Char32 = self.SqlType("VARCHAR(32) CHARACTER SET utf8mb4") 39 | val Utf8Char64 = self.SqlType("VARCHAR(64) CHARACTER SET utf8mb4") 40 | val Utf8Char128 = self.SqlType("VARCHAR(128) CHARACTER SET utf8mb4") 41 | val Utf8Char255 = self.SqlType("VARCHAR(255) CHARACTER SET utf8mb4") 42 | val Utf8BinChar8 = self.SqlType("VARCHAR(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin") 43 | val Utf8BinChar16 = self.SqlType("VARCHAR(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin") 44 | val Utf8BinChar32 = self.SqlType("VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin") 45 | val Utf8BinChar64 = self.SqlType("VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin") 46 | val Utf8BinChar128 = self.SqlType("VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin") 47 | val Utf8BinChar255 = self.SqlType("VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin") 48 | val DateTime = self.SqlType("DATETIME") 49 | val Date = self.SqlType("DATE") 50 | val Time = self.SqlType("TIME") 51 | val Ts = self.SqlType("TIMESTAMP DEFAULT CURRENT_TIMESTAMP") 52 | val TsCurrent = self.SqlType("TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") 53 | val Text = self.SqlType("TEXT CHARACTER SET utf8mb4") 54 | val Blob = self.SqlType("BLOB") 55 | def Decimal(m: Int, d: Int) = self.SqlType(s"DECIMAL($m, $d)") 56 | } 57 | 58 | trait SlickColumnOptionOps { 59 | implicit def slickColumnOptionsExtension(co: STC#ColumnOptions) = 60 | new SlickColumnOptionsExtension(co) 61 | } 62 | -------------------------------------------------------------------------------- /framework/ixias-aws-sns/src/main/scala/ixias/aws/sns/backend/AmazonSNSConfig.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.sns.backend 10 | 11 | import scala.util.Try 12 | import scala.collection.JavaConverters._ 13 | import com.amazonaws.regions.Regions 14 | import com.amazonaws.auth.{ AWSCredentials, BasicAWSCredentials } 15 | import ixias.util.Configuration 16 | 17 | trait AmazonSNSConfig { 18 | 19 | // --[ Properties ]----------------------------------------------------------- 20 | /** The keys of configuration */ 21 | protected val CF_SNS_ACCESS_KEY = "access_key_id" 22 | protected val CF_SNS_SECRET_KEY = "secret_access_key" 23 | protected val CF_SNS_REGION = "region" 24 | protected val CF_SNS_OPT_SNS_SKIP = "skip" 25 | protected val CF_SNS_OPT_SNS_TOPIC_ARN = "topic" 26 | 27 | /** The configuration */ 28 | protected val config = Configuration() 29 | 30 | // --[ Methods ]-------------------------------------------------------------- 31 | /** 32 | * Gets the AWS credentials object. 33 | */ 34 | protected def getAWSCredentials(implicit dsn: DataSourceName): Try[AWSCredentials] = 35 | for { 36 | akey <- getAWSAccessKeyId 37 | skey <- getAWSSecretKey 38 | } yield new BasicAWSCredentials(akey, skey) 39 | 40 | /** 41 | * Gets the AWS access key ID for this credentials object. 42 | */ 43 | protected def getAWSAccessKeyId(implicit dsn: DataSourceName): Try[String] = 44 | Try(readValue( 45 | _.get[Option[String]](CF_SNS_ACCESS_KEY)).get 46 | ) 47 | 48 | /** 49 | * Gets the AWS secret access key for this credentials object. 50 | */ 51 | protected def getAWSSecretKey(implicit dsn: DataSourceName): Try[String] = 52 | Try(readValue( 53 | _.get[Option[String]](CF_SNS_SECRET_KEY)).get 54 | ) 55 | 56 | /** 57 | * Gets a region enum corresponding to the given region name. 58 | */ 59 | protected def getAWSRegion(implicit dsn: DataSourceName): Try[Regions] = 60 | Try(Regions.fromName(readValue( 61 | _.get[Option[String]](CF_SNS_REGION)).get 62 | )) 63 | 64 | /** 65 | * Gets the flag to invoke SNS process. 66 | */ 67 | def isSkip(implicit dsn: DataSourceName): Boolean = 68 | readValue( 69 | _.get[Option[Boolean]](CF_SNS_OPT_SNS_SKIP) 70 | ).getOrElse(false) 71 | 72 | /** 73 | * Gets the topic ARN of Amazon SNS. 74 | */ 75 | def getTopicARN(implicit dsn: DataSourceName): Try[Seq[String]] = { 76 | val path = dsn.name match { 77 | case None => dsn.path + "." + dsn.resource 78 | case Some(name) => dsn.path + "." + dsn.resource + "." + name 79 | } 80 | val section = config.get[Configuration](path).underlying 81 | val opt = section.getAnyRef(CF_SNS_OPT_SNS_TOPIC_ARN) match { 82 | case v: String => Seq(v) 83 | case v: java.util.List[_] => v.asScala.toList.map(_.toString) 84 | case _ => throw new Exception(s"""Illegal value type of host setting. { path: $dsn }""") 85 | } 86 | Try(opt) 87 | } 88 | 89 | /** 90 | * Get a value by specified key. 91 | */ 92 | final private def readValue[A](f: Configuration => Option[A])(implicit dsn: DataSourceName): Option[A] = 93 | (dsn.name.toSeq.map( 94 | name => dsn.path + "." + dsn.resource + "." + name 95 | ) ++ Seq( 96 | dsn.path + "." + dsn.resource, 97 | dsn.path 98 | )).foldLeft[Option[A]](None) { 99 | case (prev, path) => prev.orElse(f(config.get[Configuration](path))) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /framework/ixias-aws-qldb/src/main/scala/ixias/aws/qldb/model/ConvOps.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.aws.qldb.model 10 | 11 | import scala.language.implicitConversions 12 | import com.amazon.ion.IonValue 13 | import software.amazon.qldb.{ Result => QldbResult } 14 | import ixias.aws.qldb.databind.DatabindModule 15 | 16 | // Conversion processing methods 17 | // to support mutual conversion between Amazon Ion and model. 18 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 | import ConvOps._ 20 | trait ConvOps { 21 | 22 | //-- [ To Amazon Ion ] ------------------------------------------------------- 23 | /** 24 | * Model -> Single IonValue value. 25 | */ 26 | implicit def convToIonValue[A](v: A): IonValue = 27 | MAPPER_FOR_WRITE_ION.writeValueAsIonValue(v) 28 | 29 | /** 30 | * Single IonValue value -> Model 31 | */ 32 | implicit def convToModel[A](v: IonValue)(implicit ctag: reflect.ClassTag[A]): A = 33 | MAPPER_FOR_READ_ION.readValue(v, ctag.runtimeClass).asInstanceOf[A] 34 | 35 | //-- [ From AmazonQldb Result ] ---------------------------------------------- 36 | implicit def toQldbResultTransformer(v: QldbResult) = 37 | QldbResultTransformer(v) 38 | } 39 | 40 | // Companion object 41 | //~~~~~~~~~~~~~~~~~~ 42 | object ConvOps { 43 | import com.fasterxml.jackson.annotation.{ JsonInclude, JsonProperty, JsonIgnoreProperties } 44 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule 45 | import com.fasterxml.jackson.dataformat.ion.IonObjectMapper 46 | import com.fasterxml.jackson.databind.{ SerializationFeature, DeserializationFeature } 47 | import com.fasterxml.jackson.module.scala.DefaultScalaModule 48 | 49 | //- Ignore serialize of id field 50 | @JsonIgnoreProperties(Array("id")) 51 | case class ShapeMixIn(@JsonProperty("id") id: Option[AnyVal]) 52 | 53 | /** Mapper for AmazonIon object. */ 54 | lazy val MAPPER_FOR_READ_ION = { 55 | val mapper = new IonObjectMapper() 56 | mapper.registerModule(new JavaTimeModule) 57 | .registerModule(DefaultScalaModule) 58 | .registerModule(DatabindModule) 59 | .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) 60 | .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) 61 | .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) 62 | mapper 63 | } 64 | 65 | /** Mapper for AmazonIon object. */ 66 | lazy val MAPPER_FOR_WRITE_ION = { 67 | val mapper = new IonObjectMapper() 68 | mapper.registerModule(new JavaTimeModule) 69 | .registerModule(DefaultScalaModule) 70 | .registerModule(DatabindModule) 71 | .setSerializationInclusion(JsonInclude.Include.NON_ABSENT) 72 | .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) 73 | .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) 74 | .addMixIn(classOf[ixias.model.EntityModel[_]], classOf[ShapeMixIn]) 75 | mapper 76 | } 77 | } 78 | 79 | // Transformer for QldbResult 80 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 81 | case class QldbResultTransformer(self: QldbResult) extends AnyVal { 82 | 83 | /** To Seq[Model] */ 84 | def toModelSeq[A](implicit ctag: reflect.ClassTag[A]): Seq[A] = { 85 | val cls = ctag.runtimeClass 86 | toIonValueSeq.map( 87 | MAPPER_FOR_READ_ION.readValue(_, cls).asInstanceOf[A] 88 | ) 89 | } 90 | 91 | /** 92 | * AmazonQLDB Result -> IonValue rows. 93 | */ 94 | def toIonValueSeq: Seq[IonValue] = { 95 | import collection.JavaConverters._ 96 | val list = new java.util.ArrayList[IonValue]() 97 | self.iterator().forEachRemaining(v => list.add(v)) 98 | Seq(list.asScala: _*) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /framework/ixias-core/src/main/scala/ixias/util/json/JsonEnvReads.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.util.json 10 | 11 | import play.api.libs.json._ 12 | import play.api.libs.json.EnvReads 13 | import scala.util.{ Try, Success, Failure } 14 | 15 | /** 16 | * Reads Conbinator for type conversion in service 17 | */ 18 | trait JsonEnvReads extends EnvReads { 19 | 20 | /** 21 | * Deserializer for ixias.model.@@[Long, _] 22 | */ 23 | def idAsNumberReads[T <: ixias.model.@@[Long, _]]: Reads[T] = 24 | new Reads[T] { 25 | def reads(json: JsValue) = json match { 26 | case JsNumber(n) if n.isValidLong => { 27 | val Id = ixias.model.the[ixias.model.Identity[T]] 28 | JsSuccess(Id(n.toLong.asInstanceOf[T])) 29 | } 30 | case JsNumber(n) => JsError("error.expected.tag.long") 31 | case _ => JsError("error.expected.tag.jsnumber") 32 | } 33 | } 34 | 35 | /** 36 | * Deserializer for ixias.model.@@[String, _] 37 | */ 38 | def idAsStrReads[T <: ixias.model.@@[String, _]]: Reads[T] = 39 | new Reads[T] { 40 | def reads(json: JsValue) = json match { 41 | case JsString(s) => { 42 | val Id = ixias.model.the[ixias.model.Identity[T]] 43 | JsSuccess(Id(s.asInstanceOf[T])) 44 | } 45 | case _ => JsError("error.expected.tag.jsstring") 46 | } 47 | } 48 | 49 | /** 50 | * Deserializer for ixias.util.EnumStatus 51 | */ 52 | def enumReads[E <: ixias.util.EnumStatus](enum: ixias.util.EnumStatus.Of[E]): Reads[E] = 53 | new Reads[E] { 54 | def reads(json: JsValue) = json match { 55 | case JsNumber(n) if n.isValidShort => JsSuccess(enum(n.toShort)) 56 | case JsNumber(n) => JsError("error.expected.enum.short") 57 | case _ => JsError("error.expected.enum.jsnumber") 58 | } 59 | } 60 | 61 | /** 62 | * Deserializer for ixias.util.EnumStatusAsStr 63 | */ 64 | def enumReads[E <: ixias.util.EnumStatusAsStr](enum: ixias.util.EnumStatusAsStr.Of[E]): Reads[E] = 65 | new Reads[E] { 66 | def reads(json: JsValue) = json match { 67 | case JsString(n) => JsSuccess(enum(n)) 68 | case _ => JsError("error.expected.enum.jsnumber") 69 | } 70 | } 71 | 72 | /** 73 | * Deserializer for ixias.util.EnumBitFlags 74 | */ 75 | def enumReads[E <: ixias.util.EnumBitFlags](enum: ixias.util.EnumBitFlags.Of[E]): Reads[Seq[E]] = 76 | new Reads[Seq[E]] { 77 | def reads(json: JsValue) = json match { 78 | case JsNumber(n) if n.isValidLong => JsSuccess(enum(n.toLong)) 79 | case JsNumber(n) => JsError("error.expected.enum.long") 80 | case _ => JsError("error.expected.enum.jsnumber") 81 | } 82 | } 83 | 84 | /** 85 | * Deserializer for java.time.YearMonth 86 | */ 87 | implicit object YearMonthReads extends Reads[java.time.YearMonth] { 88 | def reads(json: JsValue) = json match { 89 | case JsNumber(millis) => 90 | JsSuccess(java.time.YearMonth.now( 91 | java.time.Clock.fixed( 92 | java.time.Instant.ofEpochMilli(millis.toLong), 93 | java.time.ZoneOffset.UTC 94 | ) 95 | )) 96 | case JsString(s) => { 97 | val fmt = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM") 98 | Try(java.time.YearMonth.parse(s, fmt)) match { 99 | case Success(v) => JsSuccess(v) 100 | case Failure(_) => JsError(JsonValidationError("error.expected.date.format", fmt)) 101 | } 102 | } 103 | case _ => for { 104 | v1 <- (json \ "year" ).validate[Int] 105 | v2 <- (json \ "month").validate[Int] 106 | } yield java.time.YearMonth.of(v1, v2) 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /framework/ixias-play-core/src/main/scala/ixias/play/api/mvc/binder/Id.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright ixias.net All Rights Reserved. 3 | * 4 | * Use of this source code is governed by an MIT-style license 5 | * For the full copyright and license information, 6 | * please view the LICENSE file that was distributed with this source code. 7 | */ 8 | 9 | package ixias.play.api.mvc.binder 10 | 11 | import play.api.mvc.{ PathBindable, QueryStringBindable } 12 | 13 | /** 14 | * Binder utility function for ID implemented in Tagged-Type 15 | * 16 | * 17 | * type UserId = Long @@ UserModel 18 | * implicit val pathBindForUserId = pathBindableBoxId[UserId] 19 | * implicit val queryBindForUserId = queryStringBindableBoxId[UserId] 20 | */ 21 | trait IdBindable extends Box { 22 | 23 | // -- [ PathBindable ] ------------------------------------------------------- 24 | /** 25 | * PathBindable: ixias.model.@@[Long, _] 26 | */ 27 | def pathBindableBoxId[T <: ixias.model.@@[_, _]] 28 | (implicit ctag: reflect.ClassTag[T]): PathBindable[Box[T]] = { 29 | val Id = ixias.model.the[ixias.model.Identity[T]] 30 | new PathBindable.Parsing[Box[T]]( 31 | (s: String) => { 32 | val id = ctag.runtimeClass match { 33 | case x if classOf[Int].isAssignableFrom(x) => Id(s.toInt.asInstanceOf[T]) 34 | case x if classOf[Long].isAssignableFrom(x) => Id(s.toLong.asInstanceOf[T]) 35 | case x if classOf[String].isAssignableFrom(x) => Id(s.asInstanceOf[T]) 36 | case _ => throw new IllegalArgumentException( 37 | "Unsupported type of id-value: %s".format(ctag.runtimeClass) 38 | ) 39 | } 40 | () => id 41 | }, 42 | (v: Box[T]) => Id.unwrap(v).toString, 43 | (key: String, e: Exception) => { 44 | "Cannot parse parameter %s as ixias.model.@@[_, _]\n %s".format(key, e) 45 | } 46 | ) 47 | } 48 | 49 | // -- [ QueryStringBindable ] ------------------------------------------------ 50 | /** 51 | * For ixias.model.@@[_, _] 52 | */ 53 | def queryStringBindableBoxId[T <: ixias.model.@@[_, _]] 54 | (implicit ctag: reflect.ClassTag[T]): QueryStringBindable[Box[T]] = { 55 | val Id = ixias.model.the[ixias.model.Identity[T]] 56 | new QueryStringBindable.Parsing[Box[T]]( 57 | (s: String) => { 58 | val id = ctag.runtimeClass match { 59 | case x if classOf[Int].isAssignableFrom(x) => Id(s.toInt.asInstanceOf[T]) 60 | case x if classOf[Long].isAssignableFrom(x) => Id(s.toLong.asInstanceOf[T]) 61 | case x if classOf[String].isAssignableFrom(x) => Id(s.asInstanceOf[T]) 62 | case _ => throw new IllegalArgumentException( 63 | "Unsupported type of id-value: %s".format(ctag.runtimeClass) 64 | ) 65 | } 66 | () => id 67 | }, 68 | (v: Box[T]) => Id.unwrap(v).toString, 69 | (key: String, e: Exception) => { 70 | "Cannot parse parameter %s as ixias.model.@@[_, _]\n %s".format(key, e) 71 | } 72 | ) 73 | } 74 | 75 | /** 76 | * For ixias.model.@@[_, _] 77 | */ 78 | def queryStringBindableBoxCsvId[T <: ixias.model.@@[_, _]] 79 | (implicit ctag: reflect.ClassTag[T]): QueryStringBindable[BoxCsv[T]] = { 80 | val Id = ixias.model.the[ixias.model.Identity[T]] 81 | new QueryStringBindable.Parsing[BoxCsv[T]]( 82 | (s: String) => { 83 | val ids: Seq[T] = s.split(",").map(tok => 84 | ctag.runtimeClass match { 85 | case x if classOf[Int].isAssignableFrom(x) => Id(tok.toInt.asInstanceOf[T]) 86 | case x if classOf[Long].isAssignableFrom(x) => Id(tok.toLong.asInstanceOf[T]) 87 | case x if classOf[String].isAssignableFrom(x) => Id(tok.asInstanceOf[T]) 88 | case _ => throw new IllegalArgumentException( 89 | "Unsupported type of id-value: %s".format(ctag.runtimeClass) 90 | ) 91 | } 92 | ) 93 | () => ids 94 | }, 95 | (v: BoxCsv[T]) => v.map( 96 | id => Id.unwrap(id).toString 97 | ).mkString(","), 98 | (key: String, e: Exception) => { 99 | "Cannot parse parameter %s as ixias.model.@@[_, _]\n %s".format(key, e) 100 | } 101 | ) 102 | } 103 | } 104 | --------------------------------------------------------------------------------