
com.comcast.xfinity.sirius.api.impl.SiriusFactory.scala Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2012-2014 Comcast Cable Communications Management, LLC
*
* 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.comcast.xfinity.sirius.api.impl
import java.io.File
import java.lang.management.ManagementFactory
import java.net.InetAddress
import java.util.{HashMap => JHashMap}
import com.comcast.xfinity.sirius.admin.ObjectNameHelper
import com.comcast.xfinity.sirius.api.{BrainlessRequestHandler, RequestHandler, SiriusConfiguration}
import com.comcast.xfinity.sirius.info.SiriusInfo
import com.comcast.xfinity.sirius.writeaheadlog.CachedSiriusLog
import com.comcast.xfinity.sirius.writeaheadlog.SiriusLog
import com.typesafe.config.{Config, ConfigFactory}
import akka.actor.ActorRef
import akka.actor.ActorSystem
import javax.management.ObjectName
import com.comcast.xfinity.sirius.uberstore.segmented.SegmentedUberStore
import com.comcast.xfinity.sirius.uberstore.UberStore
import com.comcast.xfinity.sirius.util.AkkaExternalAddressResolver
import scala.collection.JavaConverters._
import org.slf4j.LoggerFactory
import scala.concurrent.Await
import scala.concurrent.duration.Duration
/**
* Provides the factory for [[com.comcast.xfinity.sirius.api.impl.SiriusImpl]] instances
*/
object SiriusFactory {
val traceLog = LoggerFactory.getLogger("SiriusFactory")
/**
* SiriusImpl factory method, takes parameters to construct a SiriusImplementation and the dependent
* ActorSystem and return the created instance. Calling shutdown on the produced SiriusImpl will also
* shutdown the dependent ActorSystem.
*
* @param requestHandler the RequestHandler containing callbacks for manipulating the system's state
* @param siriusConfig a SiriusConfiguration containing configuration info needed for this node.
* @see SiriusConfiguration for info on needed config.
*
* @return A SiriusImpl constructed using the parameters
*/
def createInstance(requestHandler: RequestHandler, siriusConfig: SiriusConfiguration): SiriusImpl = {
val uberStoreDir = siriusConfig.getProp[String](SiriusConfiguration.LOG_LOCATION) match {
case Some(dir) => dir
case None =>
throw new IllegalArgumentException(SiriusConfiguration.LOG_LOCATION + " must be set on config")
}
val backendLog = {
siriusConfig.getProp(SiriusConfiguration.LOG_VERSION_ID, "") match {
case version if version == SegmentedUberStore.versionId => SegmentedUberStore(uberStoreDir, siriusConfig)
case _ => UberStore(uberStoreDir, siriusConfig)
}
}
val log: SiriusLog = {
if (siriusConfig.getProp(SiriusConfiguration.LOG_USE_WRITE_CACHE, true)) {
val cacheSize = siriusConfig.getProp(SiriusConfiguration.LOG_WRITE_CACHE_SIZE, 10000)
CachedSiriusLog(backendLog, cacheSize)
} else {
backendLog
}
}
createInstance(requestHandler, siriusConfig, log)
}
/**
* Helper method for returning the [[BrainlessRequestHandler]] case object instance
*/
def brainlessRequestHandler(): RequestHandler = BrainlessRequestHandler
/**
* USE ONLY FOR TESTING HOOK WHEN YOU NEED TO MOCK OUT A LOG.
* Real code should use the two argument factory method.
*
* @param requestHandler the RequestHandler containing callbacks for manipulating the system's state
* @param siriusConfig a SiriusConfiguration containing configuration info needed for this node.
* @see SiriusConfiguration for info on needed config.
* @param siriusLog the persistence layer to which events should be committed to and replayed from.
*
* @return A SiriusImpl constructed using the parameters
*/
private[sirius] def createInstance(requestHandler: RequestHandler, siriusConfig: SiriusConfiguration,
siriusLog: SiriusLog): SiriusImpl = {
val systemName = siriusConfig.getProp(SiriusConfiguration.AKKA_SYSTEM_NAME, "sirius-system")
implicit val actorSystem = ActorSystem(systemName, createActorSystemConfig(siriusConfig))
// inject an mbean server, without regard for the one that may have been there
val mbeanServer = ManagementFactory.getPlatformMBeanServer
siriusConfig.setProp(SiriusConfiguration.MBEAN_SERVER, mbeanServer)
// inject AkkaExternalAddressResolver
siriusConfig.setProp(SiriusConfiguration.AKKA_EXTERNAL_ADDRESS_RESOLVER, AkkaExternalAddressResolver(actorSystem) (siriusConfig))
// here it is! the real deal creation
val impl = SiriusImpl(requestHandler, siriusLog, siriusConfig)
// create a SiriusInfo MBean which will remain registered until we explicitly shutdown sirius
val (siriusInfoObjectName, siriusInfo) = createSiriusInfoMBean(actorSystem, impl.supervisor)(siriusConfig)
mbeanServer.registerMBean(siriusInfo, siriusInfoObjectName)
// need to shut down the actor system and unregister the mbeans when sirius is done
impl.onShutdown({
Await.ready(actorSystem.terminate(), Duration.Inf)
mbeanServer.unregisterMBean(siriusInfoObjectName)
})
impl
}
private def createSiriusInfoMBean(actorSystem: ActorSystem, siriusSup: ActorRef)
(siriusConfig: SiriusConfiguration): (ObjectName, SiriusInfo) = {
val resolver = siriusConfig.getProp[AkkaExternalAddressResolver](SiriusConfiguration.AKKA_EXTERNAL_ADDRESS_RESOLVER).
getOrElse(throw new IllegalStateException("SiriusConfiguration.AKKA_EXTERNAL_ADDRESS_RESOLVER returned nothing"))
val siriusInfo = new SiriusInfo(actorSystem, siriusSup, resolver)
val objectNameHelper = new ObjectNameHelper
val siriusInfoObjectName = objectNameHelper.getObjectName(siriusInfo, siriusSup, actorSystem)(siriusConfig)
(siriusInfoObjectName, siriusInfo)
}
/**
* Creates configuration for the ActorSystem. The config precedence is as follows:
* 1) host/port config trump all
* 2) siriusConfig supplied external config next
* 3) sirius-akka-base.conf, packaged with sirius, loaded with ConfigFactory.load
*/
private def createActorSystemConfig(siriusConfig: SiriusConfiguration): Config = {
val hostPortConfig = createHostPortConfig(siriusConfig)
val externalConfig = createExternalConfig(siriusConfig)
val baseAkkaConfig = ConfigFactory.load("sirius-akka-base.conf")
hostPortConfig.withFallback(externalConfig).withFallback(baseAkkaConfig)
}
private def createHostPortConfig(siriusConfig: SiriusConfiguration): Config = {
val configMap = new JHashMap[String, Any]()
val sslEnabled = siriusConfig.getProp(SiriusConfiguration.ENABLE_SSL, false)
val transportPrefix = if (sslEnabled) "akka.remote.netty.ssl" else "akka.remote.netty.tcp"
traceLog.info(s"AKKA using transport: $transportPrefix")
configMap.put("akka.remote.enabled-transports", List(transportPrefix).asJava)
configMap.put(s"$transportPrefix.hostname",
siriusConfig.getProp(SiriusConfiguration.HOST, InetAddress.getLocalHost.getHostName))
configMap.put(s"$transportPrefix.port", siriusConfig.getProp(SiriusConfiguration.PORT, 2552))
val maxMessageSize = siriusConfig.getInt(SiriusConfiguration.MAX_AKKA_MESSAGE_SIZE_KB, 1024)
val bufferSize = maxMessageSize * 2
configMap.put(s"$transportPrefix.maximum-frame-size", s"${maxMessageSize}k")
configMap.put(s"$transportPrefix.send-buffer-size", s"${bufferSize}k")
configMap.put(s"$transportPrefix.receive-buffer-size", s"${bufferSize}k")
if (sslEnabled) {
configMap.put(s"$transportPrefix.random-number-generator",
siriusConfig.getProp(SiriusConfiguration.SSL_RANDOM_NUMBER_GENERATOR, ""))
configMap.put(s"$transportPrefix.security.key-store",
siriusConfig.getProp(SiriusConfiguration.KEY_STORE_LOCATION,
throw new IllegalArgumentException("No key-store provided")))
configMap.put(s"$transportPrefix.security.trust-store",
siriusConfig.getProp(SiriusConfiguration.TRUST_STORE_LOCATION,
throw new IllegalArgumentException("No trust-store provided")))
configMap.put(s"$transportPrefix.security.key-store-password",
siriusConfig.getProp(SiriusConfiguration.KEY_STORE_PASSWORD,
throw new IllegalArgumentException("No key-store-password value provided")))
configMap.put(s"$transportPrefix.security.key-password",
siriusConfig.getProp(SiriusConfiguration.KEY_PASSWORD,
throw new IllegalArgumentException("No key-password value provided")))
configMap.put(s"$transportPrefix.security.trust-store-password",
siriusConfig.getProp(SiriusConfiguration.TRUST_STORE_PASSWORD,
throw new IllegalArgumentException("No trust-store-password value provided")))
}
// this is just so that the intellij shuts up
ConfigFactory.parseMap(configMap.asInstanceOf[JHashMap[String, _ <: AnyRef]])
}
/**
* If siriusConfig is such configured, will load up an external configuration
* for the Akka ActorSystem which is created. The filesystem is checked first,
* then the classpath, if neither exist, or siriusConfig is not configured as
* much, then an empty Config object is returned.
*/
private def createExternalConfig(siriusConfig: SiriusConfiguration): Config =
siriusConfig.getProp[String](SiriusConfiguration.AKKA_EXTERN_CONFIG) match {
case None => ConfigFactory.empty()
case Some(externConfig) =>
val externConfigFile = new File(externConfig)
if (externConfigFile.exists()) {
ConfigFactory.parseFile(externConfigFile).resolve()
} else {
ConfigFactory.parseResources(externConfig).resolve()
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy