Codacy: Imports should be sorted alphabetically

If you’re developing Scala apps and let them be checked by Codacy, you might have enabled the check “Imports should be sorted alphabetically“.
What sounds easy, isn’t in fact.

Here are my findings, summarised as example imports.

import akka.actor.ActorRef

import akka.Done // upper/lowercase doesn't matter
import akka.streams.Source

import java.util.ArrayList // this needs to be in the middle of the packages, most IDEs put it into an extra block

import mycompany.mypackage._ // underscore is always before

import mycompany.mypackage.mysubpackage.mysubsubpackage.A

import mycompany.mypackage.{ClassA, ClassB, ClassC}
import mycompany.otherpackage.SomeProtocol // space before dot 
import mycompany.otherpackage.SomeProtocol.{MessageA, MessageB}
import org.slf4j.LoggerFactory
import pureconfig._ // again, underscore before
import pureconfig.generic.{ExportMacros, ProductHint}
import scala.concurrent.{ExecutionContext, Future}
import scala.collection.JavaConverters._
import scala.io.Source
import scala.util.{Failure, Success} // normal IDEs put all scala.* classes into an extra block at the end of all import statements
import slick.basic.DatabaseConfig
import slick.jdbc.JdbcProfile

I hope this helps someone.. I’m sure, I’ll check back on this page in about a week again….

PlayFramework: Delay a route / response

In an event-sourced environment, you sometimes have to introduce an artificial delay to some actions to make sure read-sides had the time to update themselves. If you’re using the classic routing mechanism with a routes-file, you can add such a delay declaratively, like here:

+ delay800
PUT   /products/:productId          controllers.ProductCRUDController.update(productId: UUID)

This would delay the response of the update-action by 800 Milliseconds, hopefully giving the other consuming services enough time to catch up.

To make this work, you have to add a filter to your application, like this one:

import akka.actor.ActorSystem
import akka.stream.Materializer
import play.api.mvc.{Filter, RequestHeader, Result}
import play.api.routing.Router
import scala.concurrent.duration._
import scala.concurrent.{ExecutionContext, Future}

class DelayFilter(val mat: Materializer, implicit val ec: ExecutionContext, actorSystem: ActorSystem) extends Filter {

  override def apply(nextFilter: RequestHeader => Future[Result])(rh: RequestHeader): Future[Result] = {
    val handler = rh.attrs.get(Router.Attrs.HandlerDef)
    val delay: Option[Int] = handler
      .flatMap(
        _.modifiers
          .find(s => s.startsWith("delay")))
      .map(s => Integer.parseInt(s.substring("delay".length)))
      .filter(_ > 0)

    val result = nextFilter.apply(rh)
    delay match {
      case Some(d) => akka.pattern.after(d.millis, actorSystem.scheduler)(result)
      case None => result
    }
  }
}

and of course, enable the filter in your application.conf

play.filters.enabled+=mypackage.filters.DelayFilter

Did this help you in your project? Let me know in the comments!

PlayFramework Evolutions & PostgreSQL Stored Procedures

If you have to create a stored procedure in your PlayFramework Database Evolution Script, make sure to properly escape your semicolons (by using two semicolons):

CREATE OR REPLACE FUNCTION user_insert_update_query_function()
RETURNS TRIGGER AS $$
BEGIN
  NEW.query := lower(NEW.firstname) || '|' || lower(NEW.lastname);;
  RETURN NEW;;
END;;
$$ LANGUAGE 'plpgsql';

Kodi: Play VIDEO_TS folder

I recently wanted to play a DVD, where I only had the bare folder structure. KODI is supposed to support this, but its not working yet, so I ended up creating the dvd-image on my server myself.

This assumes, that you have stored the VIDEO_TS folder in my_dvd

# add an additional AUDIO_TS folder
mkdir my_dvd/AUDIO_TS
# create a iso from the folders
genisoimage -dvd-video -v -o my.iso my_dvd/

Thanks to Ron999 in the Ubuntu-Forums

PlayFramework: Serve a file from the classpath

Recently, I’ve implemented a Swagger-API with Play. As I’ve published a new version of the API, I wanted to make a CHANGELOG available.

So the question was, where to store this file.. a blog or some other external resource felt plainly wrong, so I decided to put it right next to the code.

class ChangeLogController (cc: ControllerComponents) extends AbstractController(cc) {

  implicit val ec: ExecutionContext = cc.executionContext

  def changeLog = cc.actionBuilder.apply { req =>
    val clazz = this.getClass

    val resource = Option(clazz.getResourceAsStream(“/de/some/package/structure/api/v1_1/CHANGELOG.txt”))

    resource
      .map(s => StreamConverters.fromInputStream(() => s))
      .map(source => {
        Result(
          header = ResponseHeader(play.api.http.Status.OK, Map.empty, None),
          body = HttpEntity.Streamed(source, None, Some(“text/plain”))
        )
      })
      .getOrElse(Results.InternalServerError(“failed to load file from classpath”))
  }

}

Omnicharge Settings for MacBook Pro 15″ Mid 2015 Retina

I have a MacBook Pro 15″ Mid-2015 Retina. It uses a 85W MagSafe 2 Power Adapter, which is emitting max 4.25 Ampere at 20 Volts.




According to

https://omnicharge.zendesk.com/hc/en-us/articles/115000623608-Step-3-How-to-use-DC-output, that means,
I’ll have to configure my OmniCharge to 20V DC Output

 

To do this:

  • Turn the Omnicharge on
  • Double Click the Power button, Menu appears
  • Click the Power Button to enter DC Configuration
  • Use the UP-DOWN Arrows to select “Presets”, press Power Button to enter
  • Select 20V, use Power Button to select
  • Change to “Yes”, use Power Button to confirm
  • Done

 

Akka-Streams: Zip first element of one source with every element of other source

The code looked like this:

val futureSet: Future[Set[ProductId]] = noIndexRepository.findAll()
val noIndexSource: Source[Set[ProductId], NotUsed] = Source.fromFuture(futureSet) // basically a Source.single() 
val productsSource: Source[product.Product, NotUsed] = productRepository.getAllProducts(tenant)

after looking at the implementation of zipWithIndex, I came up with this solution:

val source: Source[(product.Product, Set[ProductId]), NotUsed] = noIndexSource
  .flatMapConcat(x => productsSource.statefulMapConcat { () ⇒
    elem ⇒ {
      val zipped = (elem, x)
      immutable.Iterable[(product.Product, Set[ProductId])](zipped)
    }
  })

val filteredSource = source.filterNot(x => x._2.contains(x._1.id)).map(_._1)

val f = filteredSource.via(flow).runWith(Sink.ignore)(materializer)

Do you know of a easier way to accomplish this? Let me know in the comments!

Note to self: Play-WS Scala send POST Request Multipart/Form-Data

import play.api.mvc.MultipartFormData._

val url = "http://someAddress.com/withPostEndpoint"

val params: immutable.Iterable[DataPart] = Map(
  "from" -> "sender@host.com",
  "to" -> "user@host.com",
  "subject" -> "mySubject",
  "text" ->
    s"""
       |Hallo!
       |blablabla
       | """.stripMargin
).map { case (k, v) => DataPart(k, v) }

val parameterSource = Source.fromIterator(() => params.toIterator)

val f = wsClient
  .url(url)
  .post(parameterSource)

Note to Self: PlayFramework split routes-file

File “conf/routes”:
->      /api                        api.Routes // focus on the big R!
->      /                           website.Routes
File “conf/api.routes”:
GET    /healthCheck/status                              api.controllers.HealthCheck.status
GET    /healthCheck/version                             api.controllers.HealthCheck.version
file “conf/website.routes”:
GET    /                         controllers.Home.index
GET    /robots.txt               controllers.Assets.at(path=”/public”, file=”robots.txt”)
GET    /assets/*file             controllers.Assets.at(path=”/public”, file)
GET    /profile                  controllers.Users.profile

 

 

 

 

Note to self: PlayFramework disable IPv6

To make sure that your Play! Application binds on an IPv4 Socket in your Docker-Container, add the following to your build.sbt file

javaOptions in Universal ++= Seq( // docker
....
  "-Djava.net.preferIPv4Stack=true"
)
javaOptions in run += "-Djava.net.preferIPv4Stack=true" // dev mode

when running locally, you can also start sbt and tell it to prefer the IPv4 Stack.

sbt -J-Djava.net.preferIPv4Stack=true