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

com.datamountaineer.streamreactor.connect.jms.JMSSessionProvider.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017 Datamountaineer.
 *
 * 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.datamountaineer.streamreactor.connect.jms

import java.util.Properties
import javax.jms._
import javax.naming.InitialContext

import com.datamountaineer.streamreactor.connect.jms.config.DestinationSelector.DestinationSelector
import com.datamountaineer.streamreactor.connect.jms.config._
import com.typesafe.scalalogging.slf4j.StrictLogging
import org.apache.kafka.common.config.types.Password
import org.apache.kafka.connect.errors.ConnectException

import scala.util.control.NonFatal
import scala.util.{Failure, Success, Try}

/**
  * Created by [email protected] on 10/03/2017. 
  * stream-reactor
  */
case class JMSSessionProvider(queueConsumers: Map[String, MessageConsumer],
                              topicsConsumers: Map[String, MessageConsumer],
                              queueProducers : Map[String, MessageProducer],
                              topicProducers : Map[String, MessageProducer],
                              session: Session,
                              connection: Connection,
                              context: InitialContext) extends StrictLogging {

  def start(): Unit = {
    logger.info(s"Starting connection to ${connection.toString}")
    connection.start()
  }

  def close(): Try[Unit] =
    for {
      _ <- Try(connection.close())
      _ <- Try(context.close())
    } yield ()
}

object JMSSessionProvider extends StrictLogging {
  def apply(settings: JMSSettings, sink: Boolean = false): JMSSessionProvider =
    withConnection(settings){ (context, connection) =>
      val session = Try(connection.createSession(sink, Session.CLIENT_ACKNOWLEDGE)) match {
        case Success(s) =>
          logger.info("Created session")
          s
        case Failure(f) =>
          logger.error("Failed to create session", f.getMessage)
          throw new ConnectException(f)
      }

      if (sink) {
        val topicProducers = configureDestination(TopicDestination, context, session, settings, sink)
          .flatMap({ case (source, _, topic) => createProducers(source, session, topic) }).toMap

        val queueProducers = configureDestination(QueueDestination, context, session, settings, sink)
          .flatMap({ case (source, _, queue) => createProducers(source, session, queue) }).toMap
        new JMSSessionProvider(Map[String, MessageConsumer](), Map[String, MessageConsumer](), queueProducers, topicProducers, session, connection, context)
      } else {
        val topicsConsumers = configureDestination(TopicDestination, context, session, settings, sink)
          .flatMap({ case (source, ms, topic) => createConsumers(source, session, topic, settings.subscriptionName, ms) }).toMap
        val queueConsumers = configureDestination(QueueDestination, context, session, settings, sink)
          .flatMap({ case (source, ms, queue) => createConsumers(source, session, queue, settings.subscriptionName, ms) }).toMap
        new JMSSessionProvider(queueConsumers, topicsConsumers, Map[String, MessageProducer](), Map[String, MessageProducer](), session, connection, context)
      }
  }

  def configureDestination(destinationType: DestinationType, context: InitialContext, session: Session, settings: JMSSettings, sink: Boolean = false): List[(String, Option[String], Destination)] = {
    settings.settings
      .filter(f => f.destinationType.equals(destinationType))
      .map(t => (t.source, t.messageSelector, getDestination(if (sink) t.target else t.source, context, settings.destinationSelector, destinationType, session)))
  }

  def createProducers(source: String, session: Session, destination: Destination) = Map(source -> session.createProducer(destination))

  def createConsumers(source: String, session: Session, destination: Destination, subscriptionName: Option[String], messageSelector: Option[String]) = Map(source -> {
    val selector = messageSelector.getOrElse(null)
    subscriptionName match {
      case None => session.createConsumer(destination, selector)
      case Some(name) => 
        destination match {
          case destination: Topic => session.createSharedDurableConsumer(destination, name, selector)
          case _ => session.createConsumer(destination, selector)
        }
    }
  })

  private def withConnection[T](settings: JMSSettings)(f: (InitialContext, Connection) => T): T = {
    val context: InitialContext =  new InitialContext(getProps(settings))
    val connectionFactory = context.lookup(settings.connectionFactoryClass).asInstanceOf[ConnectionFactory]
    val connection = settings.user match {
      case None => connectionFactory.createConnection()
      case Some(user) => connectionFactory.createConnection(user, settings.password.get.value())
    }
    try {
      f(context, connection)
    } catch {
      case NonFatal(e) =>
        connection.close()
        throw e
    }
  }

  private def getDestination(name: String, context: InitialContext, selector: DestinationSelector,
                             destination: DestinationType, session: Session): Destination = {
    selector match {
      case DestinationSelector.JNDI => context.lookup(name).asInstanceOf[Destination]
      case DestinationSelector.CDI =>
        destination match {
          case QueueDestination => session.createQueue(name)
          case TopicDestination => session.createTopic(name)
        }
    }
  }

  /**
    * Construct the properties for the initial context
    * adding in anything in the extra properties for solace or ibm
    *
    * */
  private def getProps(settings: JMSSettings) = {
    val props = new Properties()
    props.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, settings.initialContextClass)
    props.setProperty(javax.naming.Context.PROVIDER_URL, settings.connectionURL)
    props.setProperty(javax.naming.Context.SECURITY_PRINCIPAL, settings.user.getOrElse(""))
    props.setProperty(javax.naming.Context.SECURITY_CREDENTIALS, settings.password.getOrElse(new Password("")).value())
    settings.extraProps.map(e => e.map { case (k,v) => props.setProperty(k, v) })
    props
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy