diff --git a/apps/shrine-app/src/main/scala/net/shrine/wiring/ManuallyWiredShrineJaxrsResources.scala b/apps/shrine-app/src/main/scala/net/shrine/wiring/ManuallyWiredShrineJaxrsResources.scala index 95ae89494..51d0b811c 100644 --- a/apps/shrine-app/src/main/scala/net/shrine/wiring/ManuallyWiredShrineJaxrsResources.scala +++ b/apps/shrine-app/src/main/scala/net/shrine/wiring/ManuallyWiredShrineJaxrsResources.scala @@ -1,380 +1,383 @@ package net.shrine.wiring import com.typesafe.config.ConfigFactory import net.shrine.adapter.Adapter import net.shrine.adapter.AdapterMap import net.shrine.adapter.DeleteQueryAdapter import net.shrine.adapter.FlagQueryAdapter import net.shrine.adapter.ReadInstanceResultsAdapter import net.shrine.adapter.ReadPreviousQueriesAdapter import net.shrine.adapter.ReadQueryDefinitionAdapter import net.shrine.adapter.ReadQueryResultAdapter import net.shrine.adapter.ReadTranslatedQueryDefinitionAdapter import net.shrine.adapter.RenameQueryAdapter import net.shrine.adapter.RunQueryAdapter import net.shrine.adapter.UnFlagQueryAdapter import net.shrine.adapter.dao.AdapterDao import net.shrine.adapter.dao.I2b2AdminDao import net.shrine.adapter.dao.squeryl.SquerylAdapterDao import net.shrine.adapter.dao.squeryl.SquerylI2b2AdminDao import net.shrine.adapter.dao.squeryl.tables.{Tables => AdapterTables} import net.shrine.adapter.service.AdapterRequestHandler import net.shrine.adapter.service.AdapterResource import net.shrine.adapter.service.AdapterService import net.shrine.adapter.service.I2b2AdminResource import net.shrine.adapter.service.I2b2AdminService import net.shrine.adapter.translators.ExpressionTranslator import net.shrine.adapter.translators.QueryDefinitionTranslator import net.shrine.authentication.Authenticator import net.shrine.authorization.QueryAuthorizationService import net.shrine.broadcaster.AdapterClientBroadcaster import net.shrine.broadcaster.BroadcastAndAggregationService import net.shrine.broadcaster.BroadcasterClient import net.shrine.broadcaster.InJvmBroadcasterClient import net.shrine.broadcaster.NodeHandle import net.shrine.broadcaster.PosterBroadcasterClient import net.shrine.broadcaster.SigningBroadcastAndAggregationService import net.shrine.log.Loggable import net.shrine.service.dao.AuditDao import net.shrine.service.dao.squeryl.SquerylAuditDao import net.shrine.service.dao.squeryl.tables.{Tables => HubTables} import net.shrine.broadcaster.service.BroadcasterMultiplexerResource import net.shrine.broadcaster.service.BroadcasterMultiplexerService import net.shrine.client.{EndpointConfig, HttpClient, JerseyHttpClient, OntClient, Poster, PosterOntClient} import net.shrine.config.mappings.AdapterMappings import net.shrine.config.mappings.AdapterMappingsSource import net.shrine.config.mappings.ClasspathFormatDetectingAdapterMappingsSource import net.shrine.crypto.DefaultSignerVerifier import net.shrine.crypto.KeyStoreCertCollection import net.shrine.dao.squeryl.DataSourceSquerylInitializer import net.shrine.dao.squeryl.SquerylDbAdapterSelecter import net.shrine.ont.data.OntClientOntologyMetadata import net.shrine.protocol.NodeId import net.shrine.protocol.RequestType import net.shrine.protocol.ResultOutputType import net.shrine.happy.HappyShrineResource import net.shrine.happy.HappyShrineService import net.shrine.service.I2b2BroadcastResource import net.shrine.service.I2b2BroadcastService import net.shrine.service.ShrineResource import net.shrine.service.ShrineService import net.shrine.crypto.TrustParam import javax.sql.DataSource +import net.shrine.status.StatusJaxrs import org.squeryl.internals.DatabaseAdapter import net.shrine.dao.squeryl.SquerylInitializer import net.shrine.ont.data.OntologyMetadata import net.shrine.broadcaster.dao.HubDao import net.shrine.broadcaster.dao.squeryl.SquerylHubDao /** * @author clint * @since Jan 14, 2014 * * Application wiring for Shrine, in the base, non-HMS case. All vals are protecetd, so they may be accessed, * in subclasses without ballooning this class's public API, and lazy, to work around init-order surprises when * overriding vals declared inline. See * * https://stackoverflow.com/questions/15762650/scala-override-val-in-class-inheritance * * among other links mentioning val overrides, early initializers, etc. -Clint */ class ManuallyWiredShrineJaxrsResources(authStrategy: AuthStrategy = AuthStrategy.Default) extends ShrineJaxrsResources with Loggable { import ManuallyWiredShrineJaxrsResources._ import NodeHandleSource.makeNodeHandles override def resources: Iterable[AnyRef] = { - Seq(happyResource) ++ shrineResource ++ i2b2BroadcastResource ++ adapterResource ++ i2b2AdminResource ++ broadcasterMultiplexerResource + Seq(happyResource,statusJaxrs) ++ shrineResource ++ i2b2BroadcastResource ++ adapterResource ++ i2b2AdminResource ++ broadcasterMultiplexerResource } //Load config from file on the classpath called "shrine.conf" protected lazy val shrineConfig: ShrineConfig = ShrineConfig(ConfigFactory.load("shrine")) protected lazy val nodeId: NodeId = NodeId(shrineConfig.humanReadableNodeName) //TODO: Don't assume keystore lives on the filesystem, could come from classpath, etc protected lazy val shrineCertCollection: KeyStoreCertCollection = KeyStoreCertCollection.fromFile(shrineConfig.keystoreDescriptor) protected lazy val keystoreTrustParam: TrustParam = TrustParam.SomeKeyStore(shrineCertCollection) protected lazy val signerVerifier: DefaultSignerVerifier = new DefaultSignerVerifier(shrineCertCollection) protected lazy val dataSource: DataSource = Jndi("java:comp/env/jdbc/shrineDB").get protected lazy val squerylAdapter: DatabaseAdapter = SquerylDbAdapterSelecter.determineAdapter(shrineConfig.shrineDatabaseType) protected lazy val squerylInitializer: SquerylInitializer = new DataSourceSquerylInitializer(dataSource, squerylAdapter) private def makePoster = poster(shrineCertCollection) _ private lazy val pmEndpoint: EndpointConfig = shrineConfig.pmEndpoint private lazy val ontEndpoint: EndpointConfig = shrineConfig.ontEndpoint protected lazy val pmPoster: Poster = makePoster(pmEndpoint) protected lazy val ontPoster: Poster = makePoster(ontEndpoint) protected lazy val breakdownTypes: Set[ResultOutputType] = shrineConfig.breakdownResultOutputTypes protected lazy val hubDao: HubDao = new SquerylHubDao(squerylInitializer, new net.shrine.broadcaster.dao.squeryl.tables.Tables) //todo move as much of this block as possible to the adapter project protected lazy val (adapterService, i2b2AdminService, adapterDao, adapterMappings) = adapterComponentsToTuple(shrineConfig.adapterConfig.map { adapterConfig => val crcEndpoint: EndpointConfig = adapterConfig.crcEndpoint val crcPoster: Poster = makePoster(crcEndpoint) val squerylAdapterTables: AdapterTables = new AdapterTables val adapterDao: AdapterDao = new SquerylAdapterDao(squerylInitializer, squerylAdapterTables)(breakdownTypes) //NB: Is i2b2HiveCredentials.projectId the right project id to use? val i2b2AdminDao: I2b2AdminDao = new SquerylI2b2AdminDao(shrineConfig.crcHiveCredentials.projectId, squerylInitializer, squerylAdapterTables) val adapterMappingsSource: AdapterMappingsSource = ClasspathFormatDetectingAdapterMappingsSource(adapterConfig.adapterMappingsFileName) //NB: Fail fast val adapterMappings: AdapterMappings = adapterMappingsSource.load.get val expressionTranslator: ExpressionTranslator = ExpressionTranslator(adapterMappings) val queryDefinitionTranslator: QueryDefinitionTranslator = new QueryDefinitionTranslator(expressionTranslator) val doObfuscation = adapterConfig.setSizeObfuscation val runQueryAdapter = new RunQueryAdapter( crcPoster, adapterDao, shrineConfig.crcHiveCredentials, queryDefinitionTranslator, adapterConfig.adapterLockoutAttemptsThreshold, doObfuscation, adapterConfig.immediatelyRunIncomingQueries, breakdownTypes, collectAdapterAudit = adapterConfig.collectAdapterAudit ) val readInstanceResultsAdapter: Adapter = new ReadInstanceResultsAdapter( crcPoster, shrineConfig.crcHiveCredentials, adapterDao, doObfuscation, breakdownTypes, collectAdapterAudit = adapterConfig.collectAdapterAudit ) val readQueryResultAdapter: Adapter = new ReadQueryResultAdapter( crcPoster, shrineConfig.crcHiveCredentials, adapterDao, doObfuscation, breakdownTypes, collectAdapterAudit = adapterConfig.collectAdapterAudit ) val readPreviousQueriesAdapter: Adapter = new ReadPreviousQueriesAdapter(adapterDao) val deleteQueryAdapter: Adapter = new DeleteQueryAdapter(adapterDao) val renameQueryAdapter: Adapter = new RenameQueryAdapter(adapterDao) val readQueryDefinitionAdapter: Adapter = new ReadQueryDefinitionAdapter(adapterDao) val readTranslatedQueryDefinitionAdapter: Adapter = new ReadTranslatedQueryDefinitionAdapter(nodeId, queryDefinitionTranslator) val flagQueryAdapter: Adapter = new FlagQueryAdapter(adapterDao) val unFlagQueryAdapter: Adapter = new UnFlagQueryAdapter(adapterDao) val adapterMap = AdapterMap(Map( RequestType.QueryDefinitionRequest -> runQueryAdapter, RequestType.GetRequestXml -> readQueryDefinitionAdapter, RequestType.UserRequest -> readPreviousQueriesAdapter, RequestType.InstanceRequest -> readInstanceResultsAdapter, RequestType.MasterDeleteRequest -> deleteQueryAdapter, RequestType.MasterRenameRequest -> renameQueryAdapter, RequestType.GetQueryResult -> readQueryResultAdapter, RequestType.ReadTranslatedQueryDefinitionRequest -> readTranslatedQueryDefinitionAdapter, RequestType.FlagQueryRequest -> flagQueryAdapter, RequestType.UnFlagQueryRequest -> unFlagQueryAdapter)) AdapterComponents( new AdapterService(nodeId, signerVerifier, adapterConfig.maxSignatureAge, adapterMap), new I2b2AdminService(adapterDao, i2b2AdminDao, pmPoster, runQueryAdapter), adapterDao, adapterMappings) }) private val localAdapterServiceOption: Option[AdapterRequestHandler] = shrineConfig.hubConfig.flatMap(hubConfig => makeAdapterServiceOption(hubConfig.shouldQuerySelf, adapterService)) private val broadcastDestinations: Option[Set[NodeHandle]] = shrineConfig.hubConfig.map(hubConfig => makeNodeHandles(keystoreTrustParam, hubConfig.maxQueryWaitTime, hubConfig.downstreamNodes, nodeId, localAdapterServiceOption, breakdownTypes)) protected lazy val (shrineService, i2b2Service, auditDao) = queryEntryPointComponentsToTuple(shrineConfig.queryEntryPointConfig.map { queryEntryPointConfig => val broadcasterClient: BroadcasterClient = { if(queryEntryPointConfig.broadcasterIsLocal) { //If broadcaster is local, we need a hub config //TODO: Enforce this when unmarshalling configs require(broadcastDestinations.isDefined, "Local broadcaster specified, but no downstream nodes defined") val broadcaster: AdapterClientBroadcaster = AdapterClientBroadcaster(broadcastDestinations.get, hubDao) InJvmBroadcasterClient(broadcaster) } else { //if broadcaster is remote, we need an endpoint //TODO: Enforce this when unmarshalling configs require(queryEntryPointConfig.broadcasterServiceEndpoint.isDefined, "Non-local broadcaster requested, but no URL for the remote broadcaster is specified") PosterBroadcasterClient(makePoster(queryEntryPointConfig.broadcasterServiceEndpoint.get), breakdownTypes) } } val commonName:String = shrineCertCollection.myCommonName.getOrElse{ val hostname = java.net.InetAddress.getLocalHost.getHostName warn(s"No common name available from ${shrineCertCollection.descriptor}. Using $hostname instead.") hostname } val broadcastService: BroadcastAndAggregationService = SigningBroadcastAndAggregationService(broadcasterClient, signerVerifier, queryEntryPointConfig.signingCertStrategy) val auditDao: AuditDao = new SquerylAuditDao(squerylInitializer, new HubTables) val authenticationType = queryEntryPointConfig.authenticationType val authorizationType = queryEntryPointConfig.authorizationType val authenticator: Authenticator = authStrategy.determineAuthenticator(authenticationType, pmPoster) val authorizationService: QueryAuthorizationService = authStrategy.determineQueryAuthorizationService(authorizationType, shrineConfig, authenticator) debug(s"authorizationService set to $authorizationService") QueryEntryPointComponents( ShrineService( commonName, auditDao, authenticator, authorizationService, queryEntryPointConfig.includeAggregateResults, broadcastService, queryEntryPointConfig.maxQueryWaitTime, breakdownTypes, queryEntryPointConfig.collectQepAudit ), I2b2BroadcastService( commonName, auditDao, authenticator, authorizationService, queryEntryPointConfig.includeAggregateResults, broadcastService, queryEntryPointConfig.maxQueryWaitTime, breakdownTypes, queryEntryPointConfig.collectQepAudit ), auditDao) }) private lazy val broadcasterOption = unpackHubComponents { for { hubConfig <- shrineConfig.hubConfig } yield { require(broadcastDestinations.isDefined, "This node is configured to be a hub, but no downstream nodes are defined") HubComponents(AdapterClientBroadcaster(broadcastDestinations.get, hubDao)) } } protected lazy val broadcasterMultiplexerService = { for { broadcaster <- broadcasterOption hubConfig <- shrineConfig.hubConfig } yield { BroadcasterMultiplexerService(broadcaster, hubConfig.maxQueryWaitTime) } } protected lazy val pmUrlString: String = shrineConfig.pmEndpoint.url.toString protected lazy val ontologyMetadata: OntologyMetadata = { import scala.concurrent.duration._ //TODO: XXX: Un-hard-code max wait time param val ontClient: OntClient = new PosterOntClient(shrineConfig.ontHiveCredentials, 1.minute, ontPoster) new OntClientOntologyMetadata(ontClient) } //TODO: Don't assume we're an adapter with an AdapterMappings (don't call .get) protected lazy val happyService: HappyShrineService = { new HappyShrineService( shrineConfig, shrineCertCollection, signerVerifier, pmPoster, ontologyMetadata, adapterMappings, auditDao, adapterDao, broadcasterOption, adapterService) } protected lazy val happyResource: HappyShrineResource = new HappyShrineResource(happyService) + protected lazy val statusJaxrs: StatusJaxrs = StatusJaxrs() + protected lazy val shrineResource: Option[ShrineResource] = shrineService.map(ShrineResource(_)) protected lazy val i2b2BroadcastResource: Option[I2b2BroadcastResource] = i2b2Service.map(new I2b2BroadcastResource(_, breakdownTypes)) protected lazy val adapterResource: Option[AdapterResource] = adapterService.map(AdapterResource(_)) protected lazy val i2b2AdminResource: Option[I2b2AdminResource] = i2b2AdminService.map(I2b2AdminResource(_, breakdownTypes)) protected lazy val broadcasterMultiplexerResource: Option[BroadcasterMultiplexerResource] = broadcasterMultiplexerService.map(BroadcasterMultiplexerResource(_)) } object ManuallyWiredShrineJaxrsResources { def makeAdapterServiceOption(isQueryable: Boolean, adapterRequestHandler: Option[AdapterRequestHandler]): Option[AdapterRequestHandler] = { if (isQueryable) { require(adapterRequestHandler.isDefined, "Self-querying requested, but this node is not configured to be an adapter") adapterRequestHandler } else { None } } def makeHttpClient(keystoreCertCollection: KeyStoreCertCollection, endpoint: EndpointConfig): HttpClient = { import TrustParam.{ AcceptAllCerts, SomeKeyStore } val trustParam = if (endpoint.acceptAllCerts) AcceptAllCerts else SomeKeyStore(keystoreCertCollection) JerseyHttpClient(trustParam, endpoint.timeout) } private final case class AdapterComponents(adapterService: AdapterService, i2b2AdminService: I2b2AdminService, adapterDao: AdapterDao, adapterMappings: AdapterMappings) private final case class QueryEntryPointComponents(shrineService: ShrineService, i2b2Service: I2b2BroadcastService, auditDao: AuditDao) private final case class HubComponents(broadcaster: AdapterClientBroadcaster) //TODO: TEST private def adapterComponentsToTuple(option: Option[AdapterComponents]): (Option[AdapterService], Option[I2b2AdminService], Option[AdapterDao], Option[AdapterMappings]) = option match { case None => (None, None, None, None) case Some(AdapterComponents(a, b, c, d)) => (Option(a), Option(b), Option(c), Option(d)) } //TODO: TEST private def queryEntryPointComponentsToTuple(option: Option[QueryEntryPointComponents]): (Option[ShrineService], Option[I2b2BroadcastService], Option[AuditDao]) = option match { case None => (None, None, None) case Some(QueryEntryPointComponents(a, b, c)) => (Option(a), Option(b), Option(c)) } //TODO: TEST private def unpackHubComponents(option: Option[HubComponents]): Option[AdapterClientBroadcaster] = option.map(_.broadcaster) def poster(keystoreCertCollection: KeyStoreCertCollection)(endpoint: EndpointConfig): Poster = { val httpClient = makeHttpClient(keystoreCertCollection, endpoint) Poster(endpoint.url.toString, httpClient) } }