<commit_before>package xitrum.routing

import scala.collection.mutable.{Map => MMap}

import akka.actor.{Actor, ActorRef, ActorRefFactory, Props}
import com.esotericsoftware.reflectasm.ConstructorAccess

import xitrum.{Config, Log, SockJsAction}

/**
 * "websocket" and "cookieNeeded" members are named after SockJS options, ex:
 * {"websocket": true, "cookie_needed": false, "origins": ["*:*"], "entropy": 123}
 *
 * - websocket: true means WebSocket is enabled
 * - cookieNeeded: true means load balancers needs JSESSION cookie
 */
class SockJsClassAndOptions(
    val actorClass:   Class[_ <: SockJsAction],
    val websocket:    Boolean,
    val cookieNeeded: Boolean
) extends Serializable

class SockJsRouteMap(map: MMap[String, SockJsClassAndOptions]) extends Log {
  def logRoutes() {
    // This method is only run once on start, speed is not a problem

    if (!map.isEmpty) {
      val (pathPrefixMaxLength, handlerClassNameMaxLength, websocketOptionMaxLength) =
        map.toList.foldLeft((0, 0, "websocket: true,".length)) {
            case ((pmax, hmax, wmax), (pathPrefix, sockJsClassAndOptions)) =>
          val plen  = pathPrefix.length
          val hlen  = sockJsClassAndOptions.actorClass.getName.length
          val pmax2 = if (pmax < plen) plen else pmax
          val hmax2 = if (hmax < hlen) hlen else hmax
          val wmax2 = if (sockJsClassAndOptions.websocket) wmax else "websocket: false,".length
          (pmax2, hmax2, wmax2)
        }
      val logFormat = "%-" + pathPrefixMaxLength + "s  %-" + handlerClassNameMaxLength + "s  %-" + websocketOptionMaxLength + "s %s"

      val strings = map.map { case (pathPrefix, sockJsClassAndOptions) =>
        logFormat.format(
          pathPrefix,
          sockJsClassAndOptions.actorClass.getName,
          "websocket: " + sockJsClassAndOptions.websocket + ",",
          "cookie_needed: " + sockJsClassAndOptions.cookieNeeded
        )
      }
      log.info("SockJS routes:\n" + strings.mkString("\n"))
    }
  }

  /** Creates actor attached to Config.actorSystem. */
  def createSockJsAction(pathPrefix: String): ActorRef = {
    createSockJsAction(Config.actorSystem, pathPrefix)
  }

  /** Creates actor attached to the given context. */
  def createSockJsAction(context: ActorRefFactory, pathPrefix: String): ActorRef = {
    val sockJsClassAndOptions = map(pathPrefix)
    val actorClass            = sockJsClassAndOptions.actorClass
    context.actorOf(Props(ConstructorAccess.get(actorClass).newInstance()))
  }

  /** @param sockJsHandlerClass Normal SockJsHandler subclass or object class */
  def findPathPrefix(sockJsActorClass: Class[_ <: SockJsAction]): String = {
    val kv = map.find { case (k, v) => v.actorClass == sockJsActorClass }
    kv match {
      case Some((k, v)) => "/" + k
      case None         => throw new Exception("Cannot lookup SockJS URL for class: " + sockJsActorClass)
    }
  }

  def lookup(pathPrefix: String) = map(pathPrefix)

  def removeByPrefix(withoutSlashPrefix: String) ={
    map.map { case (pathPrefixOfAction, sockJsClassAndOptions) =>
      if(pathPrefixOfAction.startsWith(withoutSlashPrefix)) map.remove(pathPrefixOfAction)
    }
  }
}<commit_msg>#356 Code refactoring<commit_after>package xitrum.routing

import scala.collection.mutable.{Map => MMap}

import akka.actor.{Actor, ActorRef, ActorRefFactory, Props}
import com.esotericsoftware.reflectasm.ConstructorAccess

import xitrum.{Config, Log, SockJsAction}

/**
 * "websocket" and "cookieNeeded" members are named after SockJS options, ex:
 * {"websocket": true, "cookie_needed": false, "origins": ["*:*"], "entropy": 123}
 *
 * - websocket: true means WebSocket is enabled
 * - cookieNeeded: true means load balancers needs JSESSION cookie
 */
class SockJsClassAndOptions(
    val actorClass:   Class[_ <: SockJsAction],
    val websocket:    Boolean,
    val cookieNeeded: Boolean
) extends Serializable

class SockJsRouteMap(map: MMap[String, SockJsClassAndOptions]) extends Log {
  def logRoutes() {
    // This method is only run once on start, speed is not a problem

    if (!map.isEmpty) {
      val (pathPrefixMaxLength, handlerClassNameMaxLength, websocketOptionMaxLength) =
        map.toList.foldLeft((0, 0, "websocket: true,".length)) {
            case ((pmax, hmax, wmax), (pathPrefix, sockJsClassAndOptions)) =>
          val plen  = pathPrefix.length
          val hlen  = sockJsClassAndOptions.actorClass.getName.length
          val pmax2 = if (pmax < plen) plen else pmax
          val hmax2 = if (hmax < hlen) hlen else hmax
          val wmax2 = if (sockJsClassAndOptions.websocket) wmax else "websocket: false,".length
          (pmax2, hmax2, wmax2)
        }
      val logFormat = "%-" + pathPrefixMaxLength + "s  %-" + handlerClassNameMaxLength + "s  %-" + websocketOptionMaxLength + "s %s"

      val strings = map.map { case (pathPrefix, sockJsClassAndOptions) =>
        logFormat.format(
          pathPrefix,
          sockJsClassAndOptions.actorClass.getName,
          "websocket: " + sockJsClassAndOptions.websocket + ",",
          "cookie_needed: " + sockJsClassAndOptions.cookieNeeded
        )
      }
      log.info("SockJS routes:\n" + strings.mkString("\n"))
    }
  }

  /** Creates actor attached to Config.actorSystem. */
  def createSockJsAction(pathPrefix: String): ActorRef = {
    createSockJsAction(Config.actorSystem, pathPrefix)
  }

  /** Creates actor attached to the given context. */
  def createSockJsAction(context: ActorRefFactory, pathPrefix: String): ActorRef = {
    val sockJsClassAndOptions = map(pathPrefix)
    val actorClass            = sockJsClassAndOptions.actorClass
    context.actorOf(Props(ConstructorAccess.get(actorClass).newInstance()))
  }

  /** @param sockJsHandlerClass Normal SockJsHandler subclass or object class */
  def findPathPrefix(sockJsActorClass: Class[_ <: SockJsAction]): String = {
    val kv = map.find { case (k, v) => v.actorClass == sockJsActorClass }
    kv match {
      case Some((k, v)) => "/" + k
      case None         => throw new Exception("Cannot lookup SockJS URL for class: " + sockJsActorClass)
    }
  }

  def lookup(pathPrefix: String) = map(pathPrefix)

  def removeByPrefix(withoutSlashPrefix: String) = {
    map.map { case (pathPrefixOfAction, sockJsClassAndOptions) =>
      if (pathPrefixOfAction.startsWith(withoutSlashPrefix)) map.remove(pathPrefixOfAction)
    }
  }
}
{'fraction_non_alphanumeric': 0.11126760563380282, 'fraction_numerical': 0.003912363067292645, 'mean_word_length': 3.4723582925122463, 'pattern_counts': {'":': 8, '<': 11, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5930481', 'n_tokens_mistral': 1998, 'n_tokens_neox': 1930, 'n_words': 479}