diff --git a/apps/meta-app/pom.xml b/apps/meta-app/pom.xml index 755bdc7b6..b4c7cf465 100644 --- a/apps/meta-app/pom.xml +++ b/apps/meta-app/pom.xml @@ -1,129 +1,129 @@ <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>shrine-base</artifactId> <groupId>net.shrine</groupId> <version>1.23.5.1-SNAPSHOT</version> <relativePath>../../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>meta-app</artifactId> <name>MetaData App</name> <packaging>jar</packaging> <build> <plugins> <plugin> <groupId>net.alchim31.maven</groupId> <artifactId>scala-maven-plugin</artifactId> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>com.propensive</groupId> <artifactId>rapture-json_2.11</artifactId> <version>${rapture-version}</version> </dependency> <dependency> <groupId>com.propensive</groupId> <artifactId>rapture-json-jawn_2.11</artifactId> <version>${rapture-version}</version> </dependency> <dependency> <groupId>net.shrine</groupId> <artifactId>shrine-utility-commons</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>net.shrine</groupId> <artifactId>shrine-config</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>net.shrine</groupId> <artifactId>shrine-auth</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>net.shrine</groupId> - <artifactId>shrine-messagequeue</artifactId> + <artifactId>shrine-hornetqclient</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>net.shrine</groupId> <artifactId>shrine-qep</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </dependency> <dependency> <groupId>io.spray</groupId> <artifactId>spray-routing_2.11</artifactId> <version>${spray-version}</version> </dependency> <dependency> <groupId>io.spray</groupId> <artifactId>spray-servlet_2.11</artifactId> <version>${spray-version}</version> </dependency> <dependency> <groupId>io.spray</groupId> <artifactId>spray-util_2.11</artifactId> <version>${spray-version}</version> </dependency> <dependency> <groupId>io.spray</groupId> <artifactId>spray-testkit_2.11</artifactId> <version>${spray-version}</version> <scope>test</scope> </dependency> <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-actor_2.11</artifactId> <version>${akka-version}</version> </dependency> <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-slf4j_2.11</artifactId> <version>${akka-version}</version> </dependency> <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-testkit_2.11</artifactId> <version>${akka-testkit-version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.json4s</groupId> <artifactId>json4s-native_2.11</artifactId> <version>${json4s-version}</version> </dependency> <dependency> <groupId>com.typesafe</groupId> <artifactId>config</artifactId> <version>${typesafe-config-version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-version}</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j-version}</version> <scope>test</scope> </dependency> </dependencies> </project> \ No newline at end of file diff --git a/apps/meta-app/src/main/scala/net/shrine/metadata/MetaDataService.scala b/apps/meta-app/src/main/scala/net/shrine/metadata/MetaDataService.scala index d9ef06f7b..8cc0c7c05 100644 --- a/apps/meta-app/src/main/scala/net/shrine/metadata/MetaDataService.scala +++ b/apps/meta-app/src/main/scala/net/shrine/metadata/MetaDataService.scala @@ -1,71 +1,71 @@ package net.shrine.metadata import akka.event.Logging import net.shrine.authentication.UserAuthenticator import net.shrine.i2b2.protocol.pm.User import net.shrine.log.Loggable -import net.shrine.messagequeue.hornetqmom.HornetQMomWebApi +import net.shrine.hornetqmom.HornetQMomWebApi import net.shrine.source.ConfigSource import spray.http.{HttpRequest, HttpResponse} import spray.routing.directives.LogEntry import spray.routing.{HttpService, _} import scala.concurrent.ExecutionContext /** * An outer API to mix in sub services */ trait MetaDataService extends HttpService with StaticDataService with QepService with HornetQMomWebApi with Loggable { lazy val route: Route = logRequestResponse(logEntryForRequestResponse _) { //logging is controlled by Akka's config, slf4j, and log4j config metaDataRoute ~ hornetQMomRoute ~ staticDataRoute ~ authenticatedRoute } //todo use this val shrineInfo = """ |The SHRINE Metadata service. | |This web API gives you access to sub-services within this shrine node. |You can access these services by calling shrine-medadata/[service name]. |You can learn more about each service by calling shrine-metadata/[service name] |for top-level information about each. """.stripMargin /** logs the request method, uri and response at info level */ def logEntryForRequestResponse(req: HttpRequest): Any => Option[LogEntry] = { case res: HttpResponse => Some(LogEntry(s"\n Request: $req\n Response: $res", Logging.InfoLevel)) case _ => None // other kind of responses } /** logs just the request method, uri and response status at info level */ def logEntryForRequest(req: HttpRequest): Any => Option[LogEntry] = { case res: HttpResponse => Some(LogEntry(s"\n Request: $req\n Response status: ${res.status}", Logging.InfoLevel)) case _ => None // other kind of responses } /****/ lazy val metaDataRoute: Route = get { path("ping") { complete("pong")} ~ pathEnd {complete(shrineInfo)} } lazy val authenticatedRoute: Route = authenticate(userAuthenticator.basicUserAuthenticator) { user:User => qepRoute(user) } lazy val hornetQMomRoute: Route = momRoute lazy val userAuthenticator = UserAuthenticator(ConfigSource.config) implicit val ec: ExecutionContext } \ No newline at end of file diff --git a/messagequeue/pom.xml b/messagequeue/hornetqmom/pom.xml similarity index 64% rename from messagequeue/pom.xml rename to messagequeue/hornetqmom/pom.xml index 5bb58039a..e90e4394f 100644 --- a/messagequeue/pom.xml +++ b/messagequeue/hornetqmom/pom.xml @@ -1,113 +1,80 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <name>SHRINE Data Access Classes</name> - <artifactId>shrine-messagequeue</artifactId> + <artifactId>shrine-hornetqmom</artifactId> <packaging>jar</packaging> <parent> <groupId>net.shrine</groupId> <artifactId>shrine-base</artifactId> <version>1.23.5.1-SNAPSHOT</version> - <relativePath>../pom.xml</relativePath> + <relativePath>../../pom.xml</relativePath> </parent> <build> <sourceDirectory>src/main/scala</sourceDirectory> <testSourceDirectory>src/test/scala</testSourceDirectory> <plugins> <plugin> <groupId>net.alchim31.maven</groupId> <artifactId>scala-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <executions> <execution> <goals> <goal>test-jar</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>net.shrine</groupId> <artifactId>shrine-test-commons</artifactId> <version>${project.version}</version> <type>test-jar</type> <scope>test</scope> </dependency> <dependency> <groupId>net.shrine</groupId> <artifactId>shrine-config</artifactId> <version>${project.version}</version> </dependency> - <dependency> - <groupId>io.spray</groupId> - <artifactId>spray-util_2.11</artifactId> - <version>${spray-version}</version> - </dependency> - <dependency> - <groupId>io.spray</groupId> - <artifactId>spray-can_2.11</artifactId> - <version>1.3.4</version> - <scope>provided</scope> - </dependency> <dependency> <groupId>io.spray</groupId> <artifactId>spray-routing_2.11</artifactId> <version>${spray-version}</version> </dependency> - <dependency> - <groupId>io.spray</groupId> - <artifactId>spray-servlet_2.11</artifactId> - <version>${spray-version}</version> - </dependency> <dependency> <groupId>io.spray</groupId> <artifactId>spray-testkit_2.11</artifactId> <version>${spray-version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.json4s</groupId> <artifactId>json4s-native_2.11</artifactId> <version>${json4s-version}</version> </dependency> - <dependency> - <groupId>log4j</groupId> - <artifactId>log4j</artifactId> - </dependency> - <dependency> - <groupId>com.typesafe.akka</groupId> - <artifactId>akka-actor_2.11</artifactId> - <version>${akka-version}</version> - </dependency> <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-slf4j_2.11</artifactId> <version>${akka-version}</version> </dependency> <dependency> - <groupId>com.typesafe.akka</groupId> - <artifactId>akka-testkit_2.11</artifactId> - <version>${akka-testkit-version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-log4j12</artifactId> - <version>${slf4j-version}</version> - <scope>test</scope> + <groupId>net.shrine</groupId> + <artifactId>shrine-messagequeueservice</artifactId> + <version>${project.version}</version> </dependency> - <!-- https://mvnrepository.com/artifact/org.hornetq/hornetq-commons --> <dependency> <groupId>org.hornetq</groupId> <artifactId>hornetq-server</artifactId> <version>2.4.7.Final</version> </dependency> </dependencies> </project> diff --git a/messagequeue/hornetqmom/src/main/resources/reference.conf b/messagequeue/hornetqmom/src/main/resources/reference.conf new file mode 100644 index 000000000..9ba15e537 --- /dev/null +++ b/messagequeue/hornetqmom/src/main/resources/reference.conf @@ -0,0 +1,7 @@ +shrine { + messagequeue { + hornetq { + serverUrl = "https://localhost:6443/shrine-metadata/mom" + } + } +} \ No newline at end of file diff --git a/messagequeue/src/main/scala/net/shrine/messagequeue/hornetqmom/HornetQMomWebApi.scala b/messagequeue/hornetqmom/src/main/scala/net/shrine/hornetqmom/HornetQMomWebApi.scala similarity index 96% rename from messagequeue/src/main/scala/net/shrine/messagequeue/hornetqmom/HornetQMomWebApi.scala rename to messagequeue/hornetqmom/src/main/scala/net/shrine/hornetqmom/HornetQMomWebApi.scala index f128f1ff0..4d3385cef 100644 --- a/messagequeue/src/main/scala/net/shrine/messagequeue/hornetqmom/HornetQMomWebApi.scala +++ b/messagequeue/hornetqmom/src/main/scala/net/shrine/hornetqmom/HornetQMomWebApi.scala @@ -1,112 +1,112 @@ -package net.shrine.messagequeue.hornetqmom +package net.shrine.hornetqmom import akka.event.Logging import net.shrine.log.Loggable -import net.shrine.messagequeue.messagequeueservice.{Message, MessageSerializer, Queue} +import net.shrine.messagequeueservice.{Message, MessageSerializer, Queue} import org.json4s.native.Serialization import org.json4s.native.Serialization.{read, write} import org.json4s.{Formats, NoTypeHints} import spray.http.StatusCodes import spray.routing.directives.LogEntry import spray.routing.{HttpService, Route} import scala.collection.immutable.Seq import scala.concurrent.duration.Duration import scala.util.control.NonFatal /** * A web API that provides access to the internal HornetQMom library. * Allows client to createQueue, deleteQueue, sendMessage, receiveMessage, getQueues, and sendReceipt * * Created by yifan on 7/24/17. */ trait HornetQMomWebApi extends HttpService with Loggable { def momRoute: Route = pathPrefix("mom") { put { createQueue ~ sendMessage ~ acknowledge } ~ receiveMessage ~ getQueues ~ deleteQueue } // SQS returns CreateQueueResult, which contains queueUrl: String def createQueue: Route = path("createQueue" / Segment) { queueName => detach() { val createdQueue: Queue = LocalHornetQMom.createQueueIfAbsent(queueName) implicit val formats = Serialization.formats(NoTypeHints) val response: String = write[Queue](createdQueue)(formats) respondWithStatus(StatusCodes.Created) { complete(response) } } } // SQS takes in DeleteMessageRequest, which contains a queueUrl: String and a ReceiptHandle: String // returns a DeleteMessageResult, toString for debugging def deleteQueue: Route = path("deleteQueue" / Segment) { queueName => delete { detach() { LocalHornetQMom.deleteQueue(queueName) complete(StatusCodes.OK) } } } // SQS sendMessage(String queueUrl, String messageBody) => SendMessageResult def sendMessage: Route = path("sendMessage" / Segment / Segment) { (messageContent, toQueue) => detach() { LocalHornetQMom.send(messageContent, Queue.apply(toQueue)) complete(StatusCodes.Accepted) } } // SQS ReceiveMessageResult receiveMessage(String queueUrl) def receiveMessage: Route = get { path("receiveMessage" / Segment) { fromQueue => parameter('timeOutSeconds ? 20) { timeOutSeconds => val timeout: Duration = Duration.create(timeOutSeconds, "seconds") detach() { val response: Option[Message] = LocalHornetQMom.receive(Queue.apply(fromQueue), timeout) implicit val formats = Serialization.formats(NoTypeHints) + new MessageSerializer response.fold(complete(StatusCodes.NotFound))(msg => complete(write(response)(formats))) } } } } // SQS has DeleteMessageResult deleteMessage(String queueUrl, String receiptHandle) def acknowledge: Route = path("acknowledge") { entity(as[String]) { messageJSON => implicit val formats: Formats = Serialization.formats(NoTypeHints) + new MessageSerializer detach() { try { val msg: Message = read[Message](messageJSON)(formats, manifest[Message]) LocalHornetQMom.completeMessage(msg) complete(StatusCodes.ResetContent) } catch { case NonFatal(x) => { LogEntry(s"\n Request: acknowledge/$messageJSON\n Response: $x", Logging.DebugLevel) complete(StatusCodes.BadRequest) } } } } } // Returns the names of the queues created on this server. Seq[Any] def getQueues: Route = path("getQueues") { get { detach() { implicit val formats = Serialization.formats(NoTypeHints) respondWithStatus(StatusCodes.OK) { complete(write[Seq[Queue]](LocalHornetQMom.queues)(formats)) } } } } } \ No newline at end of file diff --git a/messagequeue/src/main/scala/net/shrine/messagequeue/hornetqmom/LocalHornetQMom.scala b/messagequeue/hornetqmom/src/main/scala/net/shrine/hornetqmom/LocalHornetQMom.scala similarity index 97% rename from messagequeue/src/main/scala/net/shrine/messagequeue/hornetqmom/LocalHornetQMom.scala rename to messagequeue/hornetqmom/src/main/scala/net/shrine/hornetqmom/LocalHornetQMom.scala index 4f9e38175..46e6d0fa7 100644 --- a/messagequeue/src/main/scala/net/shrine/messagequeue/hornetqmom/LocalHornetQMom.scala +++ b/messagequeue/hornetqmom/src/main/scala/net/shrine/hornetqmom/LocalHornetQMom.scala @@ -1,144 +1,144 @@ -package net.shrine.messagequeue.hornetqmom +package net.shrine.hornetqmom import com.typesafe.config.Config -import net.shrine.messagequeue.messagequeueservice.{Message, MessageQueueService, Queue} +import net.shrine.messagequeueservice.{Message, MessageQueueService, Queue} import net.shrine.source.ConfigSource import org.hornetq.api.core.client.{ClientConsumer, ClientMessage, ClientSession, ClientSessionFactory, HornetQClient, ServerLocator} import org.hornetq.api.core.management.HornetQServerControl import org.hornetq.api.core.{HornetQQueueExistsException, TransportConfiguration} import org.hornetq.core.config.impl.ConfigurationImpl import org.hornetq.core.remoting.impl.invm.{InVMAcceptorFactory, InVMConnectorFactory} import org.hornetq.core.server.{HornetQServer, HornetQServers} import scala.collection.immutable.Seq import scala.concurrent.blocking import scala.concurrent.duration.Duration import scala.collection.concurrent.{TrieMap, Map => ConcurrentMap} /** * This object is the local version of the Message-Oriented Middleware API, which uses HornetQ service * @author david * @since 7/18/17 */ object LocalHornetQMom extends MessageQueueService { val config:Config = ConfigSource.config.getConfig("shrine.messagequeue.hornetq") // todo use the config to set everything needed here that isn't hard-coded. val hornetQConfiguration = new ConfigurationImpl() // todo from config? What is the journal file about? If temporary, use a Java temp file. hornetQConfiguration.setJournalDirectory("target/data/journal") // todo want this. There are likely many other config bits hornetQConfiguration.setPersistenceEnabled(false) // todo maybe want this hornetQConfiguration.setSecurityEnabled(false) // todo probably just want the InVM version, but need to read up on options hornetQConfiguration.getAcceptorConfigurations.add(new TransportConfiguration(classOf[InVMAcceptorFactory].getName)) // Create and start the server val hornetQServer: HornetQServer = HornetQServers.newHornetQServer(hornetQConfiguration) hornetQServer.start() val serverLocator: ServerLocator = HornetQClient.createServerLocatorWithoutHA(new TransportConfiguration(classOf[InVMConnectorFactory].getName)) val sessionFactory: ClientSessionFactory = serverLocator.createSessionFactory() //arguments are boolean xa, boolean autoCommitSends, boolean autoCommitAcks . val session: ClientSession = sessionFactory.createSession(false,true,true) session.start() //keep a map of live queues to ClientConsumers to provide a path for completing messages val queuesToConsumers:ConcurrentMap[Queue, ClientConsumer] = TrieMap.empty val propName = "contents" /** * Use HornetQMomStopper to stop the hornetQServer without unintentially starting it */ private[hornetqmom] def stop() = { queuesToConsumers.values.foreach(_.close()) session.close() sessionFactory.close() hornetQServer.stop() } //queue lifecycle def createQueueIfAbsent(queueName:String):Queue = { val serverControl: HornetQServerControl = hornetQServer.getHornetQServerControl if(!queues.map(_.name).contains(queueName)) { try serverControl.createQueue(queueName, queueName, true) catch { case alreadyExists: HornetQQueueExistsException => //Already have what we want. Something slipped in between checking queues for this queue and creating it. } } val queue = Queue(queueName) queuesToConsumers.getOrElseUpdate(queue,{session.createConsumer(queue.name)}) queue } def deleteQueue(queueName:String) = { queuesToConsumers.remove(Queue(queueName)).foreach(_.close()) val serverControl: HornetQServerControl = hornetQServer.getHornetQServerControl serverControl.destroyQueue(queueName) } override def queues:Seq[Queue] = { val serverControl: HornetQServerControl = hornetQServer.getHornetQServerControl val queueNames: Array[String] = serverControl.getQueueNames queueNames.map(Queue(_)).to[Seq] } //send a message def send(contents:String,to:Queue):Unit = { val producer = session.createProducer(to.name) try { val message = session.createMessage(true) message.putStringProperty(propName, contents) producer.send(message) } finally { producer.close() } } //receive a message /** * Always do AWS SQS-style long polling. * Be sure your code can handle receiving the same message twice. * * @return Some message before the timeout, or None */ def receive(from:Queue,timeout:Duration):Option[Message] = { // todo check if queue exists, if not throw exception val messageConsumer: ClientConsumer = queuesToConsumers(from) //todo handle the case where either stop or close has been called on something gracefully blocking { val messageReceived: Option[ClientMessage] = Option(messageConsumer.receive(timeout.toMillis)) val message = messageReceived.map(Message(_)) message } } //todo dead letter queue for all messages. See http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/examples-sqs-dead-letter-queues.html //complete a message //todo better here or on the message itself?? override def completeMessage(message:Message):Unit = message.complete() } /** * If the configuration is such that HornetQ should have been started use this object to stop it */ //todo is this a good way to write this code? object LocalHornetQMomStopper { def stop() = { //todo fill in as part of SHIRINE-2128 val config: Config = ConfigSource.config.getConfig("shrine.messagequeue.hornetq") LocalHornetQMom.stop() } } \ No newline at end of file diff --git a/messagequeue/hornetqmom/src/test/resources/shrine.conf b/messagequeue/hornetqmom/src/test/resources/shrine.conf new file mode 100644 index 000000000..e69de29bb diff --git a/messagequeue/src/test/scala/net/shrine/messagequeue/hornetqmom/HornetQMomWebApiTest.scala b/messagequeue/hornetqmom/src/test/scala/net/shrine/hornetqmom/HornetQMomWebApiTest.scala similarity index 95% rename from messagequeue/src/test/scala/net/shrine/messagequeue/hornetqmom/HornetQMomWebApiTest.scala rename to messagequeue/hornetqmom/src/test/scala/net/shrine/hornetqmom/HornetQMomWebApiTest.scala index 63f0622d8..222bcb32d 100644 --- a/messagequeue/src/test/scala/net/shrine/messagequeue/hornetqmom/HornetQMomWebApiTest.scala +++ b/messagequeue/hornetqmom/src/test/scala/net/shrine/hornetqmom/HornetQMomWebApiTest.scala @@ -1,76 +1,76 @@ -package net.shrine.messagequeue.hornetqmom +package net.shrine.hornetqmom import akka.actor.ActorRefFactory -import net.shrine.messagequeue.messagequeueservice.{Message, MessageSerializer, Queue} +import net.shrine.messagequeueservice.{Message, MessageSerializer, Queue} import org.json4s.NoTypeHints import org.json4s.native.Serialization import org.json4s.native.Serialization.read import org.junit.runner.RunWith import org.scalatest.FlatSpec import org.scalatest.junit.JUnitRunner import spray.http.HttpEntity import spray.http.StatusCodes._ import spray.testkit.ScalatestRouteTest import scala.collection.immutable.Seq /** * Created by yifan on 7/27/17. */ @RunWith(classOf[JUnitRunner]) class HornetQMomWebApiTest extends FlatSpec with ScalatestRouteTest with HornetQMomWebApi { override def actorRefFactory: ActorRefFactory = system private val queueName = "testQueue" private val messageContent = "testContent" private var receivedMessage: String = "" "HornetQMomWebApi" should "create/delete the given queue, send/receive message, get queues" in { Put(s"/mom/createQueue/$queueName") ~> momRoute ~> check { val response = new String(body.data.toByteArray) implicit val formats = Serialization.formats(NoTypeHints) val jsonToQueue = read[Queue](response)(formats, manifest[Queue]) val responseQueueName = jsonToQueue.name assertResult(Created)(status) assertResult(queueName)(responseQueueName) } Put(s"/mom/sendMessage/$messageContent/$queueName") ~> momRoute ~> check { assertResult(Accepted)(status) } Get(s"/mom/getQueues") ~> momRoute ~> check { implicit val formats = Serialization.formats(NoTypeHints) val response: String = new String(body.data.toByteArray) val jsonToSeq: Seq[Queue] = read[Seq[Queue]](response, false)(formats, manifest[Seq[Queue]]) assertResult(OK)(status) assertResult(queueName)(jsonToSeq.head.name) } // given timeout is 2 seconds Get(s"/mom/receiveMessage/$queueName?timeOutSeconds=2") ~> momRoute ~> check { val response = new String(body.data.toByteArray) receivedMessage = response implicit val formats = Serialization.formats(NoTypeHints) + new MessageSerializer val responseToMessage: Message = read[Message](response)(formats, manifest[Message]) assertResult(OK)(status) assert(responseToMessage.isInstanceOf[Message]) } Put("/mom/acknowledge", HttpEntity(s"""$receivedMessage""")) ~> momRoute ~> check { implicit val formats = Serialization.formats(NoTypeHints) + new MessageSerializer assertResult(ResetContent)(status) } Delete(s"/mom/deleteQueue/$queueName") ~> momRoute ~> check { assertResult(OK)(status) } } } \ No newline at end of file diff --git a/messagequeue/src/test/scala/net/shrine/messagequeue/hornetqmom/LocalHornetQMomTest.scala b/messagequeue/hornetqmom/src/test/scala/net/shrine/hornetqmom/LocalHornetQMomTest.scala similarity index 96% rename from messagequeue/src/test/scala/net/shrine/messagequeue/hornetqmom/LocalHornetQMomTest.scala rename to messagequeue/hornetqmom/src/test/scala/net/shrine/hornetqmom/LocalHornetQMomTest.scala index cba9847e0..813c167e7 100644 --- a/messagequeue/src/test/scala/net/shrine/messagequeue/hornetqmom/LocalHornetQMomTest.scala +++ b/messagequeue/hornetqmom/src/test/scala/net/shrine/hornetqmom/LocalHornetQMomTest.scala @@ -1,108 +1,108 @@ -package net.shrine.messagequeue.hornetqmom +package net.shrine.hornetqmom -import net.shrine.messagequeue.messagequeueservice.Message +import net.shrine.messagequeueservice.Message import org.junit.runner.RunWith import org.scalatest.concurrent.ScalaFutures import org.scalatest.junit.JUnitRunner import org.scalatest.{BeforeAndAfterAll, FlatSpec, Matchers} import scala.collection.immutable.Seq import scala.concurrent.duration._ import scala.language.postfixOps /** * Test create, delete queue, send, and receive message, getQueueNames, and acknoledge using HornetQ service */ @RunWith(classOf[JUnitRunner]) class LocalHornetQMomTest extends FlatSpec with BeforeAndAfterAll with ScalaFutures with Matchers { "HornetQ" should "be able to send and receive just one message" in { val queueName = "testQueue" assert(LocalHornetQMom.queues.isEmpty) val queue = LocalHornetQMom.createQueueIfAbsent(queueName) assert(LocalHornetQMom.queues == Seq(queue)) val testContents = "Test message" LocalHornetQMom.send(testContents,queue) val message: Option[Message] = LocalHornetQMom.receive(queue,1 second) assert(message.isDefined) assert(message.get.contents == testContents) LocalHornetQMom.completeMessage(message.get) val shouldBeNoMessage: Option[Message] = LocalHornetQMom.receive(queue,1 second) assert(shouldBeNoMessage.isEmpty) LocalHornetQMom.deleteQueue(queueName) assert(LocalHornetQMom.queues.isEmpty) } "HornetQ" should "be able to send and receive a few messages" in { val queueName = "testQueue" assert(LocalHornetQMom.queues.isEmpty) val queue = LocalHornetQMom.createQueueIfAbsent(queueName) assert(LocalHornetQMom.queues == Seq(queue)) val testContents1 = "Test message1" LocalHornetQMom.send(testContents1,queue) val message1: Option[Message] = LocalHornetQMom.receive(queue,1 second) assert(message1.isDefined) assert(message1.get.contents == testContents1) LocalHornetQMom.completeMessage(message1.get) val shouldBeNoMessage1: Option[Message] = LocalHornetQMom.receive(queue,1 second) assert(shouldBeNoMessage1.isEmpty) val testContents2 = "Test message2" LocalHornetQMom.send(testContents2,queue) val testContents3 = "Test message3" LocalHornetQMom.send(testContents3,queue) val message2: Option[Message] = LocalHornetQMom.receive(queue,1 second) assert(message2.isDefined) assert(message2.get.contents == testContents2) LocalHornetQMom.completeMessage(message2.get) val message3: Option[Message] = LocalHornetQMom.receive(queue,1 second) assert(message3.isDefined) assert(message3.get.contents == testContents3) LocalHornetQMom.completeMessage(message3.get) val shouldBeNoMessage4: Option[Message] = LocalHornetQMom.receive(queue,1 second) assert(shouldBeNoMessage4.isEmpty) LocalHornetQMom.deleteQueue(queueName) assert(LocalHornetQMom.queues.isEmpty) } "HornetQ" should "be OK if asked to create the same queue twice " in { val queueName = "testQueue" LocalHornetQMom.createQueueIfAbsent(queueName) LocalHornetQMom.createQueueIfAbsent(queueName) LocalHornetQMom.deleteQueue(queueName) } override def afterAll() = LocalHornetQMomStopper.stop() } \ No newline at end of file diff --git a/messagequeue/src/main/resources/reference.conf b/messagequeue/src/main/resources/reference.conf deleted file mode 100644 index 79a2e5495..000000000 --- a/messagequeue/src/main/resources/reference.conf +++ /dev/null @@ -1,23 +0,0 @@ -shrine { - messagequeue { - hornetq { - serverUrl = "https://localhost:6443/shrine-metadata/mom" - } - } -} - -//todo typesafe config precedence seems to do the right thing, but I haven't found the rules that say this reference.conf should override others -akka { - loglevel = INFO - - // log-config-on-start = on - loggers = ["akka.event.slf4j.Slf4jLogger"] - // logging-filter = "akka.event.slf4j.Slf4jLoggingFilter" - // Toggles whether the threads created by this ActorSystem should be daemons or not - daemonic = on -} - -//spray.servlet { -// boot-class = "net.shrine.metadata.Boot" -// request-timeout = 30s -//} diff --git a/messagequeue/src/main/scala/net/shrine/messagequeue/hornetqclient/HornetQMomWebClient.scala b/messagequeue/src/main/scala/net/shrine/messagequeue/hornetqclient/HornetQMomWebClient.scala deleted file mode 100644 index b84651d49..000000000 --- a/messagequeue/src/main/scala/net/shrine/messagequeue/hornetqclient/HornetQMomWebClient.scala +++ /dev/null @@ -1,155 +0,0 @@ -package net.shrine.messagequeue.hornetqclient - -import akka.actor.{Actor, ActorRef, ActorRefFactory, ActorSystem, Props} -import net.shrine.log.Loggable -import net.shrine.messagequeue.messagequeueservice.HttpClient -import net.shrine.messagequeue.messagequeueservice.{Message, MessageQueueService, MessageSerializer, Queue} -import net.shrine.source.ConfigSource -import org.json4s.native.Serialization -import org.json4s.native.Serialization.{read, write} -import org.json4s.{Formats, NoTypeHints} -import spray.http.{HttpEntity, HttpMethods, HttpRequest, HttpResponse} - -import scala.collection.immutable.Seq -import scala.concurrent.ExecutionContext -import scala.concurrent.duration.Duration -import scala.util.Try -import scala.util.control.NonFatal - -/** - * A simple HornetQMomWebClient that uses HornetQMomWebApi to createQueue, - * deleteQueue, sendMessage, receiveMessage, getQueues, and sendReceipt - * - * @author yifan - * @since 8/10/17 - */ -object HornetQMomWebClient extends MessageQueueService with Loggable { - - // we need an ActorSystem to host our application in - implicit val system: ActorSystem = ActorSystem("momServer", ConfigSource.config) - - // the service actor replies to incoming HttpRequests -// implicit val serviceActor: ActorRef = startServiceActor() - -// def startActorSystem(): ActorSystem = try { -// val actorSystem: ActorSystem = ActorSystem("momServer", ConfigSource.config) -// info(s"Starting ActorSystem: ${actorSystem.name} for HornetQMomWebClient at time: ${actorSystem.startTime}") -// actorSystem -// } catch { -// case NonFatal(x) => { -// debug(s"NonFatalException thrown while starting ActorSystem for HornetQMomWebClient: ${x.getMessage}") -// throw x -// } -// case x: ExceptionInInitializerError => { -// debug(s"ExceptionInInitializerError thrown while starting ActorSystem for HornetQMomWebClient: ${x.getMessage}") -// throw x -// } -// } -// -// def startServiceActor(): ActorRef = try { -// // the service actor replies to incoming HttpRequests -// val actor: ActorRef = system.actorOf(Props[HornetQMomWebClientServiceActor]) -// info(s"Starting ServiceActor: ${actor.toString()} for HornetQMomWebClient") -// actor -// } -// catch { -// case NonFatal(x) => { -// debug(s"NonFatalException thrown while starting ServiceActor for HornetQMomWebClient: ${x.getMessage}") -// throw x -// } -// case x: ExceptionInInitializerError => { -// debug(s"ExceptionInInitializerError thrown while starting ServiceActor for HornetQMomWebClient: ${x.getMessage}") -// throw x -// } -// } - - val momUrl: String = ConfigSource.config.getString("shrine.messagequeue.hornetq.serverUrl") - - override def createQueueIfAbsent(queueName: String): Queue = { - val createQueueUrl = momUrl + s"/createQueue/$queueName" - val request: HttpRequest = HttpRequest(HttpMethods.PUT, createQueueUrl) - val tryQueue: Try[Queue] = for { - response: HttpResponse <- Try(HttpClient.webApiCall(request)) - queue: Queue <- Try { - val queueString = response.entity.asString - implicit val formats = Serialization.formats(NoTypeHints) - read[Queue](queueString)(formats, manifest[Queue]) - } - } yield queue - tryQueue.get - } - - override def deleteQueue(queueName: String): Unit = { - val deleteQueueUrl = momUrl + s"/deleteQueue/$queueName" - val request: HttpRequest = HttpRequest(HttpMethods.DELETE, deleteQueueUrl) - for { - response <- Try(HttpClient.webApiCall(request)) // StatusCodes.OK - } yield response - } - - override def queues: Seq[Queue] = { - val getQueuesUrl = momUrl + s"/getQueues" - val request: HttpRequest = HttpRequest(HttpMethods.GET, getQueuesUrl) - val tryQueues: Try[Seq[Queue]] = for { - response: HttpResponse <- Try(HttpClient.webApiCall(request)) - allQueues: Seq[Queue] <- Try { - val allQueues: String = response.entity.asString - implicit val formats = Serialization.formats(NoTypeHints) - read[Seq[Queue]](allQueues)(formats, manifest[Seq[Queue]]) - } - } yield allQueues - tryQueues.get - } - - override def send(contents: String, to: Queue): Unit = { - val sendMessageUrl = momUrl + s"/sendMessage/$contents/${to.name}" - val request: HttpRequest = HttpRequest(HttpMethods.PUT, sendMessageUrl) - for { - response: HttpResponse <- Try(HttpClient.webApiCall(request)) - } yield response - } - - override def receive(from: Queue, timeout: Duration): Option[Message] = { - val seconds = timeout.toSeconds - val receiveMessageUrl = momUrl + s"/receiveMessage/${from.name}?timeOutSeconds=$seconds" - val request: HttpRequest = HttpRequest(HttpMethods.GET, receiveMessageUrl) - val tryReceive: Try[Option[Message]] = for { - response: HttpResponse <- Try(HttpClient.webApiCall(request)) - messageResponse: Option[Message] = { - val responseString: String = response.entity.asString - implicit val formats = Serialization.formats(NoTypeHints) + new MessageSerializer - val messageResponse: Message = read[Message](responseString)(formats, manifest[Message]) - Option(messageResponse) - } - } yield messageResponse - tryReceive.get - } - - override def completeMessage(message: Message): Unit = { - implicit val formats: Formats = Serialization.formats(NoTypeHints) + new MessageSerializer - val messageString: String = write[Message](message)(formats) - - val entity: HttpEntity = HttpEntity(messageString) - val completeMessageUrl: String = momUrl + s"/acknowledge" // HttpEntity - val request: HttpRequest = HttpRequest(HttpMethods.PUT, completeMessageUrl).withEntity(entity) - for { - response: HttpResponse <- Try(HttpClient.webApiCall(request)) - } yield response - } -} - -//class HornetQMomWebClientServiceActor extends Actor with MetaDataService { -// -// // the HttpService trait defines only one abstract member, which -// // connects the services environment to the enclosing actor or test -// def actorRefFactory: ActorRefFactory = context -// -// // this actor only runs our route, but you could add -// // other things here, like request stream processing -// // or timeout handling -// def receive: Receive = runRoute(route) -// -// override implicit val ec: ExecutionContext = ExecutionContext.Implicits.global -// -// override def system: ActorSystem = context.system -//} \ No newline at end of file diff --git a/messagequeue/src/main/scala/net/shrine/messagequeue/messagequeueservice/HttpClient.scala b/messagequeue/src/main/scala/net/shrine/messagequeue/messagequeueservice/HttpClient.scala deleted file mode 100644 index c75e366c2..000000000 --- a/messagequeue/src/main/scala/net/shrine/messagequeue/messagequeueservice/HttpClient.scala +++ /dev/null @@ -1,94 +0,0 @@ -package net.shrine.messagequeue.messagequeueservice - -import java.security.cert.X509Certificate -import javax.net.ssl.{SSLContext, X509TrustManager} - -import akka.actor.{ActorRef, ActorSystem} -import akka.io.IO -import akka.pattern.ask -import net.shrine.log.Loggable -import spray.can.Http -import spray.can.Http.{ConnectionAttemptFailedException, HostConnectorSetup} -import spray.http.{HttpEntity, HttpRequest, HttpResponse, StatusCodes} -import spray.io.ClientSSLEngineProvider - -import scala.concurrent.ExecutionContext.Implicits.global -import scala.concurrent.duration.DurationInt -import scala.concurrent.{Await, Future, TimeoutException, blocking} -import scala.language.postfixOps -import scala.util.control.NonFatal - -/** - * A simple HttpClient to use inside the HttpDirectives - */ -object HttpClient extends Loggable { - - //todo hand back a Try, Failures with custom exceptions instead of a crappy response - def webApiCall(request:HttpRequest)(implicit system: ActorSystem): HttpResponse = { - val transport: ActorRef = IO(Http)(system) - - debug(s"Requesting $request uri is ${request.uri} path is ${request.uri.path}") - blocking { - val future:Future[HttpResponse] = for { - Http.HostConnectorInfo(connector, _) <- transport.ask(createConnector(request))(10 seconds) //todo make this timeout configurable - response <- connector.ask(request)(10 seconds).mapTo[HttpResponse] //todo make this timeout configurable - } yield response - try { - Await.result(future, 10 seconds) //todo make this timeout configurable - } - catch { - case x:TimeoutException => { - debug(s"${request.uri} failed with ${x.getMessage}", x) - HttpResponse(status = StatusCodes.RequestTimeout,entity = HttpEntity(s"${request.uri} timed out after 10 seconds. ${x.getMessage}")) - } - //todo is there a better message? What comes up in real life? - case x:ConnectionAttemptFailedException => { - //no web service is there to respond - debug(s"${request.uri} failed with ${x.getMessage}", x) - HttpResponse(status = StatusCodes.NotFound,entity = HttpEntity(s"${request.uri} failed with ${x.getMessage}")) - } - case NonFatal(x) => { - debug(s"${request.uri} failed with ${x.getMessage}",x) - HttpResponse(status = StatusCodes.InternalServerError,entity = HttpEntity(s"${request.uri} failed with ${x.getMessage}")) - } - } - } - } - - //from https://github.com/TimothyKlim/spray-ssl-poc/blob/master/src/main/scala/Main.scala - //trust all SSL contexts. We just want encrypted comms. - implicit val trustfulSslContext: SSLContext = { - - class IgnoreX509TrustManager extends X509TrustManager { - def checkClientTrusted(chain: Array[X509Certificate], authType: String) {} - - def checkServerTrusted(chain: Array[X509Certificate], authType: String) {} - - def getAcceptedIssuers = null - } - - val context = SSLContext.getInstance("TLS") - context.init(null, Array(new IgnoreX509TrustManager), null) - info("trustfulSslContex initialized") - context - } - - implicit val clientSSLEngineProvider = - //todo lookup this constructor - ClientSSLEngineProvider { - _ => - val engine = trustfulSslContext.createSSLEngine() - engine.setUseClientMode(true) - engine - } - - def createConnector(request: HttpRequest) = { - - val connector = new HostConnectorSetup(host = request.uri.authority.host.toString, - port = request.uri.effectivePort, - sslEncryption = request.uri.scheme == "https", - defaultHeaders = request.headers) - connector - } - -} diff --git a/messagequeue/src/main/scala/net/shrine/messagequeue/messagequeueservice/MessageQueueService.scala b/messagequeue/src/main/scala/net/shrine/messagequeue/messagequeueservice/MessageQueueService.scala deleted file mode 100644 index 89d302a2d..000000000 --- a/messagequeue/src/main/scala/net/shrine/messagequeue/messagequeueservice/MessageQueueService.scala +++ /dev/null @@ -1,62 +0,0 @@ -package net.shrine.messagequeue.messagequeueservice - -import net.shrine.spray.DefaultJsonSupport -import org.hornetq.api.core.client.ClientMessage -import org.hornetq.core.client.impl.ClientMessageImpl -import org.json4s.JsonAST.{JField, JObject} -import org.json4s.{CustomSerializer, DefaultFormats, Formats, _} - -import scala.collection.immutable.Seq -import scala.concurrent.duration.Duration -/** - * This object mostly imitates AWS SQS' API via an embedded HornetQ. See http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/examples-sqs.html - * - * @author david - * @since 7/18/17 - */ -//todo in 1.23 all but the server side will use the client RemoteHornetQ implementation (which will call to the server at the hub) -//todo in 1.24, create an AwsSqs implementation of the trait - -trait MessageQueueService { - def createQueueIfAbsent(queueName:String):Queue - def deleteQueue(queueName:String) - def queues:Seq[Queue] - def send(contents:String,to:Queue):Unit - def receive(from:Queue,timeout:Duration):Option[Message] - def completeMessage(message:Message):Unit - -} - -case class Message(hornetQMessage:ClientMessage) extends DefaultJsonSupport { - override implicit def json4sFormats: Formats = DefaultFormats - val propName = "contents" - - def getClientMessage = hornetQMessage - - def contents = hornetQMessage.getStringProperty(propName) - - def getMessageID = hornetQMessage.getMessageID - - def complete() = hornetQMessage.acknowledge() -} - -case class Queue(name:String) extends DefaultJsonSupport - -class MessageSerializer extends CustomSerializer[Message](format => ( - { - //JObject(List((hornetQMessage,JObject(List((type,JInt(0)), (durable,JBool(false)), (expiration,JInt(0)), (timestamp,JInt(1502218873012)), (priority,JInt(4))))))) - // type, durable, expiration, timestamp, priority, initialMessageBufferSize - case JObject(JField("hornetQMessage", JObject(JField("type", JInt(s)) :: JField("durable", JBool(d)) :: JField("expiration", JInt(e)) - :: JField("timestamp", JInt(t)) :: JField("priority", JInt(p)) :: Nil)) :: Nil) => - new Message(new ClientMessageImpl(s.toByte, d, e.toLong, t.toLong, p.toByte, 0)) - }, - { - case msg: Message => - JObject(JField("hornetQMessage", - JObject(JField("type", JLong(msg.getClientMessage.getType)) :: - JField("durable", JBool(msg.getClientMessage.isDurable)) :: - JField("expiration", JLong(msg.getClientMessage.getExpiration)) :: - JField("timestamp", JLong(msg.getClientMessage.getTimestamp)) :: - JField("priority", JLong(msg.getClientMessage.getPriority)) :: Nil)) :: Nil) - } -)) \ No newline at end of file diff --git a/messagequeue/src/test/hornetQMomClientTest/HornetQMomWebClientTest.scala b/messagequeue/src/test/hornetQMomClientTest/HornetQMomWebClientTest.scala deleted file mode 100644 index c2eaf988b..000000000 --- a/messagequeue/src/test/hornetQMomClientTest/HornetQMomWebClientTest.scala +++ /dev/null @@ -1,26 +0,0 @@ -/** - * A simple scala script that test HornetQMomWedClient - * - * Load the file in scala REPL to test HornetQMomWebClient - * - * Created by yifan on 8/14/17. - */ -// To Run the test, simply start the scala REPL and load the file -// Enter the following commands using the command line - -// #1. Start scala REPL with 2.11.8 version -// mvn -Dscala-version="2.11.8" scala:console - -// #2. Load file in REPL: -// :load <path-to-file> - -import net.shrine.messagequeue.hornetqclient.HornetQMomWebClient -val firstQueue = HornetQMomWebClient.createQueueIfAbsent("q1") -HornetQMomWebClient.send("firstMessage", firstQueue) -import scala.concurrent.duration.Duration -val firstDuration = Duration.create(1, "seconds") -val receivedMsg = HornetQMomWebClient.receive(firstQueue, firstDuration) -val msg = receivedMsg.get -val allQueues = HornetQMomWebClient.queues -HornetQMomWebClient.completeMessage(msg) -HornetQMomWebClient.deleteQueue("q1") \ No newline at end of file diff --git a/messagequeue/src/test/resources/shrine.conf b/messagequeue/src/test/resources/shrine.conf deleted file mode 100644 index 21eaefc60..000000000 --- a/messagequeue/src/test/resources/shrine.conf +++ /dev/null @@ -1,55 +0,0 @@ -shrine { - metaData { - ping = "pong" - five = 5 - list = [list, list, list] - object { - objectVal = 10 - } - } - problem { - problemHandler = "net.shrine.problem.NoOpProblemHandler$" - } - authenticate { - realm = "test meta service" - usersource { - //Bogus security for testing - type = "ConfigUserSource" //Must be ConfigUserSource (for isolated testing) or PmUserSource (for everything else) - researcher { - username = "ben" - password = "kapow" - } - steward { - username = "dave" - password = "kablam" - } - qep{ - username = "qep" - password = "trustme" - } - admin{ - username = "keith" - password = "shh!" - } - } - } - queryEntryPoint { - audit { - collectQepAudit = false - - database { - slickProfileClassName = "slick.driver.H2Driver$" - createTablesOnStart = true //for testing with H2 in memory, when not running unit tests. Set to false normally - - dataSourceFrom = "testDataSource" //Can be JNDI or testDataSource . Use testDataSource for tests, JNDI everywhere else - - testDataSource { - driverClassName = "org.h2.Driver" - url = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1" //H2 embedded in-memory for unit tests ;TRACE_LEVEL_SYSTEM_OUT=2 for H2's trace - } - } - } - } -} - -spray.can.server.request-timeout = 20 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 58bfb0e56..109a00e0a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,396 +1,398 @@ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <name>SHRINE</name> <groupId>net.shrine</groupId> <artifactId>shrine-base</artifactId> <packaging>pom</packaging> <version>1.23.5.1-SNAPSHOT</version> <!-- --> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.2.5.RELEASE</spring.version> <lift-version>2.6.2</lift-version> <!-- todo where do we use lift? If it's the json library, shift to json4s . Stuck on 2.6.2 due to commons/util/src/main/scala/net/shrine/serialization/JsonMarshaller.scala:21: type mismatch --> <scala-version>2.11.11</scala-version> <scala-major-version>2.11</scala-major-version> <junit-version>4.12</junit-version> <slf4j-version>1.7.22</slf4j-version> <log4j-version>1.2.17</log4j-version> <!-- todo log4j 1 is EOL. Use something else. --> <jersey-version>1.19</jersey-version> <!-- todo jersey moved into glassfish. Need to update all its dependencies--> <scalatest-version>2.2.6</scalatest-version> <!-- todo can't move to 3.0.1 due to a runtime return type check --> <scala-maven-plugin-version>3.2.2</scala-maven-plugin-version> <squeryl-version>0.9.7</squeryl-version> <typesafe-config-version>1.3.1</typesafe-config-version> <!-- 1.3.0 compiled with JDK 8--> <h2-version>1.4.193</h2-version> <easymock-version>3.4</easymock-version> <mysql-version>5.1.40</mysql-version> <opencsv-version>2.3</opencsv-version> <servlet-api-version>3.0.1</servlet-api-version><!-- for tomcat 8, you can go to 3.1.0 , but need to fix /Users/david/projects/shrine-dev/apps/proxy/src/test/scala/net/shrine/proxy/ShrineProxyServletTest.scala:119: class MockHttpServletRequest needs to be abstract --> <scallop-version>0.9.5</scallop-version><!-- Tried 1.0.0 and got compile errors todo revist next pass --> <spray-version>1.3.4</spray-version> <akka-version>2.4.16</akka-version><!-- 2.4.0 compiled with JDK 8 --> <akka-testkit-version>2.4.16</akka-testkit-version> <json4s-version>3.5.0</json4s-version> <slick-version>3.1.1</slick-version> <freeslick-version>3.1.1.1</freeslick-version> <bouncy-castle-version>1.56</bouncy-castle-version> <courier-version>0.1.3</courier-version> <mock-javamail-version>1.9</mock-javamail-version> <jjwt-version>0.7.0</jjwt-version> <jtds-version>1.3.1</jtds-version> <jawn-version>0.10.4</jawn-version> <rapture-version>2.0.0-M8</rapture-version> </properties> <!-- --> <modules> <module>apps/meta-app</module> <module>apps/meta-war</module> <module>apps/dashboard-app</module> <module>apps/dashboard-war</module> <module>apps/steward-app</module> <module>apps/steward-war</module> <module>apps/proxy</module> <module>apps/shrine-app</module> <module>apps/war</module> <module>qep/service</module> - <module>messagequeue</module> + <module>messagequeue/hornetqclient</module> + <module>messagequeue/hornetqmom</module> + <module>messagequeue/messagequeueservice</module> <module>hub/broadcaster-aggregator</module> <module>hub/broadcaster-service</module> <module>adapter/adapter-api</module> <module>adapter/adapter-service</module> <module>hms-support</module> <module>tools</module> <module>commons/json-store</module> <module>commons/util</module> <module>commons/email</module> <module>commons/auth</module> <module>commons/protocol-query</module> <module>commons/data-commons</module> <module>commons/protocol</module> <module>commons/crypto</module> <module>commons/client</module> <module>commons/config</module> <module>commons/ont-support</module> <module>commons/test-commons</module> <module>install</module> <module>integration</module> <module>shrine-webclient</module> <module>shrine-setup</module> </modules> <!-- --> <build> <pluginManagement> <plugins> <plugin> <groupId>net.alchim31.maven</groupId> <artifactId>scala-maven-plugin</artifactId> <version>${scala-maven-plugin-version}</version> <executions> <!-- Allows Java and Scala code to be compiled together and call each other --> <execution> <id>compile</id> <goals> <goal>compile</goal> </goals> <phase>compile</phase> </execution> <execution> <id>test-compile</id> <goals> <goal>testCompile</goal> </goals> <phase>test-compile</phase> </execution> <execution> <phase>process-resources</phase> <goals> <goal>compile</goal> </goals> </execution> </executions> <configuration> <!-- NB: recompileMode must be set to 'incremental' to get Zinc support; just setting useZincServer to true won't do it :( --> <recompileMode>incremental</recompileMode> <useZincServer>true</useZincServer> <jvmArgs> <jvmArg>-XX:+AggressiveOpts</jvmArg> <jvmArg>-XX:CompileThreshold=500</jvmArg> <jvmArg>-XX:+UseFastAccessorMethods</jvmArg> <jvmArg>-XX:+UseStringCache</jvmArg> <jvmArg>-XX:+OptimizeStringConcat</jvmArg> <jvmArg>-XX:+TieredCompilation</jvmArg> <jvmArg>-XX:+UseConcMarkSweepGC</jvmArg> <jvmArg>-XX:+DoEscapeAnalysis</jvmArg> <jvmArg>-server</jvmArg> <jvmArg>-Xms64m</jvmArg> <jvmArg>-Xmx1024m</jvmArg> <jvmArg>-XX:MaxPermSize=384m</jvmArg> </jvmArgs> <scalaVersion>${scala-version}</scalaVersion> <args> <arg>-Xcheckinit</arg> <arg>-unchecked</arg> <arg>-deprecation</arg> <arg>-Xlint:adapted-args,inaccessible,infer-any,missing-interpolator,private-shadow,type-parameter-shadow,unsound-match</arg> <!--<arg>-Xfatal-warnings</arg>--> </args> <source>7</source> <target>7</target> </configuration> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>7</source> <target>7</target> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>buildnumber-maven-plugin</artifactId> <!-- use explicit version because 1.0-beta-4 came with borked checksums --> <version>1.1</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.4</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.1.1</version> </plugin> </plugins> </pluginManagement> <plugins> <!-- This creates properties ${timestamp} and ${buildNumber} (the SCM revision number) --> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>buildnumber-maven-plugin</artifactId> <executions> <execution> <phase>validate</phase> <goals> <goal>create</goal> </goals> </execution> </executions> <configuration> <timestampFormat>{0,date,yyyy-MM-dd HH:mm:ss}</timestampFormat> <revisionOnScmFailure>(not available)</revisionOnScmFailure> </configuration> </plugin> <!-- Add versioning information to jars and wars --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <addDefaultImplementationEntries>true</addDefaultImplementationEntries> </manifest> <manifestEntries> <SCM-Revision>${buildNumber}</SCM-Revision> <SCM-Branch>${scmBranch}</SCM-Branch> <buildDate>${timestamp}</buildDate> </manifestEntries> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <configuration> <archive> <manifest> <addDefaultImplementationEntries>true</addDefaultImplementationEntries> </manifest> <manifestEntries> <SCM-Revision>${buildNumber}</SCM-Revision> <SCM-Branch>${scmBranch}</SCM-Branch> <buildDate>${timestamp}</buildDate> </manifestEntries> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <useTestClasspath>true</useTestClasspath> <systemProperties> <shrine.steward.gruntWatch>true</shrine.steward.gruntWatch> <shrine.steward.database.createTablesOnStart>true</shrine.steward.database.createTablesOnStart> <shrine.dashboard.gruntWatch>true</shrine.dashboard.gruntWatch> <shrine.dashboard.happyBaseUrl>http://shrine-dev1.catalyst:6060/shrine/rest/happy</shrine.dashboard.happyBaseUrl> </systemProperties> </configuration> </plugin> </plugins> </build> <!-- --> <scm> <developerConnection>scm:git:https://open.med.harvard.edu/stash/scm/shrine/shrine.git</developerConnection> </scm> <!-- --> <repositories> <!-- <repository> <id>CBMI-Nexus</id> <url>https://repo.open.med.harvard.edu/nexus/content/groups/public/</url> <snapshots> <enabled>true</enabled> </snapshots> <releases> <enabled>true</enabled> </releases> </repository> --> </repositories> <!-- --> <pluginRepositories> <pluginRepository> <id>CBMI-Nexus</id> <url>https://repo.open.med.harvard.edu/nexus/content/groups/public/</url> </pluginRepository> </pluginRepositories> <!-- --> <dependencyManagement> <dependencies> <dependency> <groupId>com.typesafe</groupId> <artifactId>config</artifactId> <version>${typesafe-config-version}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>${log4j-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>${h2-version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>${easymock-version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j-version}</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-version}</version> </dependency> <dependency> <groupId>net.sf.opencsv</groupId> <artifactId>opencsv</artifactId> <version>${opencsv-version}</version> </dependency> <dependency> <groupId>net.liftweb</groupId> <artifactId>lift-json_${scala-major-version}</artifactId> <version>${lift-version}</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> <version>${jersey-version}</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-servlet</artifactId> <version>${jersey-version}</version> </dependency> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>${jersey-version}</version> </dependency> <dependency> <groupId>org.squeryl</groupId> <artifactId>squeryl_${scala-major-version}</artifactId> <version>${squeryl-version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servlet-api-version}</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on --> <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>${bouncy-castle-version}</version> </dependency> </dependencies> </dependencyManagement> <!-- --> <dependencies> <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>${scala-version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit-version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.scalatest</groupId> <artifactId>scalatest_${scala-major-version}</artifactId> <version>${scalatest-version}</version> <scope>test</scope> <exclusions> <!-- Exclude old (Scala 2.10.0) transitive dependencies --> <exclusion> <groupId>org.scala-lang</groupId> <artifactId>scala-actors</artifactId> </exclusion> <exclusion> <groupId>org.scala-lang</groupId> <artifactId>scala-reflect</artifactId> </exclusion> </exclusions> </dependency> <!-- Re-add transitive dependencies for ScalaTest with up-to-date Scala versions --> <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-actors</artifactId> <version>${scala-version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-reflect</artifactId> <version>${scala-version}</version> </dependency> </dependencies> <!-- --> <distributionManagement> <snapshotRepository> <id>nexus</id> <name>Nexus Repo</name> <url>https://repo.open.med.harvard.edu/nexus/content/repositories/snapshots</url> <uniqueVersion>false</uniqueVersion> </snapshotRepository> <repository> <id>nexus</id> <name>Nexus Repo</name> <url>https://repo.open.med.harvard.edu/nexus/content/repositories/releases-internal</url> </repository> </distributionManagement> </project>