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

com.twitter.finatra.FinatraServer.scala Maven / Gradle / Ivy

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

import com.twitter.finagle.http.{Request => FinagleRequest, Response => FinagleResponse, HttpMuxer}
import com.twitter.finagle.http.codec.HttpServerDispatcher
import com.twitter.finagle._
import java.lang.management.ManagementFactory
import com.twitter.util.Await
import com.twitter.finagle.netty3.{Netty3ListenerTLSConfig, Netty3Listener}
import java.net.SocketAddress
import com.twitter.conversions.storage._
import com.twitter.finagle.server.DefaultServer
import com.twitter.finagle.ssl.Ssl
import java.io.{FileOutputStream, File, FileNotFoundException}

class FinatraServer extends FinatraTwitterServer {

  val controllers:  ControllerCollection = new ControllerCollection
  var filters:      Seq[Filter[FinagleRequest, FinagleResponse,FinagleRequest, FinagleResponse]] = Seq.empty
  val pid:          String = ManagementFactory.getRuntimeMXBean.getName.split('@').head

  var secureServer: Option[ListeningServer] = None
  var server:       Option[ListeningServer] = None
  var adminServer:  Option[ListeningServer] = None

  def allFilters(baseService: Service[FinagleRequest, FinagleResponse]):
    Service[FinagleRequest, FinagleResponse] = {
      filters.foldRight(baseService) { (b,a) => b andThen a }
  }

  def register(app: Controller) { controllers.add(app) }

  def addFilter(filter: Filter[FinagleRequest, FinagleResponse,FinagleRequest, FinagleResponse]) {
    filters = filters ++ Seq(filter)
  }

  def main() {
    log.info("finatra process " + pid + " started")
    start()
  }

  private[this] lazy val service = {
    val appService  = new AppService(controllers)
    val fileService = new FileService
    val loggingFilter = new LoggingFilter

    addFilter(loggingFilter)
    addFilter(fileService)

    allFilters(appService)
  }

  private[this] lazy val codec = {
    http.Http()
      .maxRequestSize(config.maxRequestSize().megabyte)
      .enableTracing(true)
      .server(ServerCodecConfig("httpserver", new SocketAddress{}))
      .pipelineFactory
  }

  def writePidFile() {
    val pidFile = new File(config.pidPath())
    val pidFileStream = new FileOutputStream(pidFile)
    pidFileStream.write(pid.getBytes)
    pidFileStream.close()
  }

  def removePidFile() {
    val pidFile = new File(config.pidPath())
    pidFile.delete()
  }

  /**
   * Allow custom TLS configuration
   */
  def getTlsConfig(): Option[Netty3ListenerTLSConfig] = {
    if (!config.certificatePath().isEmpty && !config.keyPath().isEmpty) {
      if (!new File(config.certificatePath()).canRead) {
        val e = new FileNotFoundException("SSL Certificate not found: " + config.certificatePath())
        log.fatal(e, "SSL Certificate could not be read: " + config.certificatePath())
        throw e
      }
      if (!new File(config.keyPath()).canRead) {
        val e = new FileNotFoundException("SSL Key not found: " + config.keyPath())
        log.fatal(e, "SSL Key could not be read: " + config.keyPath())
        throw e
      }

      Some(Netty3ListenerTLSConfig(() => Ssl.server(config.certificatePath(), config.keyPath(), null, null, null)))
    } else {
      None
    }
  }

  def startSecureServer() {
    getTlsConfig() foreach { tlsConfig =>
      object HttpsListener extends Netty3Listener[Any, Any]("https", codec, tlsConfig = Some(tlsConfig))
      object HttpsServer extends DefaultServer[FinagleRequest, FinagleResponse, Any, Any](
        "https", HttpsListener, new HttpServerDispatcher(_, _)
      )
      log.info("https server started on port: " + config.sslPort())
      secureServer = Some(HttpsServer.serve(config.sslPort(), service))
    }
  }

  def startHttpServer() {
    object HttpListener extends Netty3Listener[Any, Any]("http", codec)
    object HttpServer extends DefaultServer[FinagleRequest, FinagleResponse, Any, Any](
      "http", HttpListener, new HttpServerDispatcher(_, _)
    )
    log.info("http server started on port: " + config.port())
    server = Some(HttpServer.serve(config.port(), service))
  }

  def startAdminServer() {
    log.info("admin http server started on port: " + config.adminPort())
    adminServer = Some(Http.serve(config.adminPort(), HttpMuxer))
  }

  def stop() {
    server map { _.close() }
    secureServer map { _.close() }
    adminServer map { _.close() }
  }

  onExit {
    stop()
    removePidFile()
  }

  def start() {

    if (!config.pidPath().isEmpty) {
      writePidFile()
    }

    if (!config.port().isEmpty) {
      startHttpServer()
    }

    if (!config.adminPort().isEmpty) {
      startAdminServer()
    }

    if (!config.sslPort().isEmpty) {
      startSecureServer()
    }

    server       map { Await.ready(_) }
    adminServer  map { Await.ready(_) }
    secureServer map { Await.ready(_) }

  }
}






© 2015 - 2024 Weber Informatics LLC | Privacy Policy