diff --git a/commons/protocol/src/main/scala/net/shrine/protocol/FlagQueryRequest.scala b/commons/protocol/src/main/scala/net/shrine/protocol/FlagQueryRequest.scala
index fcb1a8bf9..607073141 100644
--- a/commons/protocol/src/main/scala/net/shrine/protocol/FlagQueryRequest.scala
+++ b/commons/protocol/src/main/scala/net/shrine/protocol/FlagQueryRequest.scala
@@ -1,98 +1,104 @@
package net.shrine.protocol
+import net.shrine.log.Loggable
+
import scala.concurrent.duration.Duration
import scala.util.Try
import scala.xml.NodeSeq
import net.shrine.serialization.I2b2Unmarshaller
import net.shrine.util.XmlUtil
import net.shrine.util.NodeSeqEnrichments
import net.shrine.util.XmlUtil
import scala.xml.NodeBuffer
import net.shrine.serialization.I2b2Unmarshaller
import net.shrine.serialization.I2b2UnmarshallingHelpers
/**
* @author Clint Gilbert
* @date March, 2014
*
* NB: Now needs to be serializable as an i2b2 blob, because even though flagging is a Shrine-only feature,
* flagging will be initiated from the legacy i2b2 webclient for the forseeable future. In that context,
* generating i2b2 XML blobs and running them through the proxy is the path of least resistance. Sigh.
* - 17 June 2014
*/
final case class FlagQueryRequest(
override val projectId: String,
override val waitTime: Duration,
override val authn: AuthenticationInfo,
networkQueryId: Long,
message: Option[String]) extends ShrineRequest(projectId, waitTime, authn) with HandleableI2b2Request with HasHeaderFields {
override val requestType = RequestType.FlagQueryRequest
override def handleI2b2(handler: I2b2RequestHandler, shouldBroadcast: Boolean): ShrineResponse = {
handler.flagQuery(this, shouldBroadcast)
}
import FlagQueryRequest.rootTagName
override def toXml = XmlUtil.stripWhitespace {
XmlUtil.renameRootTag(rootTagName) {
{ headerFragment }
{ networkQueryId }
{ message.map(m => { m }).orNull }
}
}
protected override def i2b2MessageBody = XmlUtil.stripWhitespace {
{ headerFragment }
{
XmlUtil.renameRootTag(rootTagName) {
{ networkQueryId }
{ message.map(m => { m }).orNull }
}
}
}
}
-object FlagQueryRequest extends I2b2XmlUnmarshaller[FlagQueryRequest] with ShrineXmlUnmarshaller[FlagQueryRequest] with ShrineRequestUnmarshaller with I2b2UnmarshallingHelpers with HasRootTagName {
+object FlagQueryRequest extends I2b2XmlUnmarshaller[FlagQueryRequest] with ShrineXmlUnmarshaller[FlagQueryRequest] with ShrineRequestUnmarshaller with I2b2UnmarshallingHelpers with HasRootTagName with Loggable {
override val rootTagName = "flagQuery"
override def fromXml(breakdownTypes: Set[ResultOutputType])(xml: NodeSeq): Try[FlagQueryRequest] = {
import NodeSeqEnrichments.Strictness._
for {
tagName <- Try(xml.head.label)
if tagName == rootTagName
projectId <- shrineProjectId(xml)
waitTimeMs <- shrineWaitTime(xml)
authn <- shrineAuthenticationInfo(xml)
networkQueryId <- xml.withChild("networkQueryId").map(_.text.toLong)
message = (xml \ "message").headOption.map(_.text)
} yield {
+ info(s"FlagQueryRequest fromXML $message from $xml")
+
FlagQueryRequest(projectId, waitTimeMs, authn, networkQueryId, message)
}
}
override def fromI2b2(breakdownTypes: Set[ResultOutputType])(xml: NodeSeq): Try[FlagQueryRequest] = {
import NodeSeqEnrichments.Strictness._
for {
projectId <- i2b2ProjectId(xml)
waitTime <- i2b2WaitTime(xml)
authn <- i2b2AuthenticationInfo(xml)
networkQueryId <- (xml withChild "message_body" withChild "request" withChild rootTagName withChild "networkQueryId").map(_.text.toLong)
message = (xml \ "message_body" \ "request" \ rootTagName \ "message").headOption.map(_.text)
} yield {
+ info(s"FlagQueryRequest fromI2b2 $message from $xml")
+
FlagQueryRequest(projectId, waitTime, authn, networkQueryId, message)
}
}
}
\ No newline at end of file
diff --git a/qep/service/src/main/scala/net/shrine/qep/ShrineResource.scala b/qep/service/src/main/scala/net/shrine/qep/ShrineResource.scala
index 089c7eec7..09a3636f4 100644
--- a/qep/service/src/main/scala/net/shrine/qep/ShrineResource.scala
+++ b/qep/service/src/main/scala/net/shrine/qep/ShrineResource.scala
@@ -1,259 +1,259 @@
package net.shrine.qep
import javax.ws.rs.Consumes
import javax.ws.rs.DELETE
import javax.ws.rs.GET
import javax.ws.rs.HeaderParam
import javax.ws.rs.POST
import javax.ws.rs.Path
import javax.ws.rs.PathParam
import javax.ws.rs.Produces
import javax.ws.rs.QueryParam
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response
import net.shrine.log.Loggable
import net.shrine.protocol.AuthenticationInfo
import net.shrine.protocol.DeleteQueryRequest
import net.shrine.protocol.OutputTypeSet
import net.shrine.protocol.ReadApprovedQueryTopicsRequest
import net.shrine.protocol.ReadInstanceResultsRequest
import net.shrine.protocol.ReadPdoRequest
import net.shrine.protocol.ReadPreviousQueriesRequest
import net.shrine.protocol.ReadQueryDefinitionRequest
import net.shrine.protocol.ReadQueryInstancesRequest
import net.shrine.protocol.ReadQueryResultRequest
import net.shrine.protocol.RenameQueryRequest
import net.shrine.protocol.RunQueryRequest
import net.shrine.protocol.ShrineRequestHandler
import net.shrine.protocol.query.QueryDefinition
import scala.xml.XML
import net.shrine.protocol.BaseShrineResponse
import net.shrine.protocol.ReadTranslatedQueryDefinitionRequest
import net.shrine.protocol.FlagQueryRequest
import net.shrine.protocol.UnFlagQueryRequest
/**
* @author Bill Simons
* @author Clint Gilbert
* @since 8/30/11
* @see http://cbmi.med.harvard.edu
* @see http://chip.org
*
* NOTICE: This software comes with NO guarantees whatsoever and is
* licensed as Lgpl Open Source
* @see http://www.gnu.org/licenses/lgpl.html
*/
@Path("/shrine")
@Produces(Array(MediaType.APPLICATION_XML)) //NB: Is a case class to get apply on the companion object, for smoother testing
final case class ShrineResource(shrineRequestHandler: ShrineRequestHandler) extends Loggable {
import ShrineResource.waitTime
@Consumes(Array(MediaType.TEXT_PLAIN))
@POST
@Path("/queries/{queryId}/flag")
def flagQuery(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") networkQueryId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean,
flagMessage: String): String = {
info(s"flagMessage string is $flagMessage")
- val flagMessageOption = Option(flagMessage).filter(!_.trim.isEmpty)
+ val flagMessageOption: Option[String] = Option(flagMessage).filter(!_.trim.isEmpty)
//TODO: What should we return, if anything?
performAndSerialize(_.flagQuery(FlagQueryRequest(projectId, waitTime, authorization, networkQueryId, flagMessageOption), shouldBroadcast))
}
@POST
@Path("/queries/{queryId}/unflag")
def unFlagQuery(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") networkQueryId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
//TODO: What should we return, if anything?
performAndSerialize(_.unFlagQuery(UnFlagQueryRequest(projectId, waitTime, authorization, networkQueryId), shouldBroadcast))
}
@GET
@Path("{userId}/approved-topics")
def readApprovedQueryTopics(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("userId") userId: String,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.readApprovedQueryTopics(ReadApprovedQueryTopicsRequest(projectId, waitTime, authorization, userId), shouldBroadcast))
}
@GET
@Path("{userId}/queries")
def readPreviousQueries(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("userId") userId: String,
@QueryParam("fetchSize") fetchSize: Int,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): Response = {
if (userId != authorization.username) {
Response.status(403).build
} else {
val fSize = if (fetchSize != 0) fetchSize else 20
Response.ok.entity {
performAndSerialize(_.readPreviousQueries(ReadPreviousQueriesRequest(projectId, waitTime, authorization, userId, fSize), shouldBroadcast))
}.build
}
}
@POST
@Path("/queries")
@Consumes(Array(MediaType.APPLICATION_XML))
def runQuery(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@HeaderParam("topicId") topicId: String,
@HeaderParam("topicName") topicName: String,
//outputTypes will be constructed by JAXRS using the String value of the 'outputTypes' header
@HeaderParam("outputTypes") outputTypes: OutputTypeSet,
queryDefinitionXml: String,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
val queryDef = QueryDefinition.fromXml(queryDefinitionXml).get
val topicIdOption = Option(topicId).filter(!_.trim.isEmpty)
val topicNameOption = Option(topicName).filter(!_.trim.isEmpty)
debug(s"runQuery() with $shrineRequestHandler and $queryDef")
performAndSerialize(_.runQuery(RunQueryRequest(projectId, waitTime, authorization, topicIdOption, topicNameOption, outputTypes.toSet, queryDef), shouldBroadcast))
}
@GET
@Path("/queries/{queryId}/instances")
def readQueryInstances(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") queryId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.readQueryInstances(ReadQueryInstancesRequest(projectId, waitTime, authorization, queryId), shouldBroadcast))
}
@GET
@Path("/instances/{instanceId}/results")
def readInstanceResults(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("instanceId") instanceId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.readInstanceResults(ReadInstanceResultsRequest(projectId, waitTime, authorization, instanceId), shouldBroadcast))
}
@POST //This must be POST, since we're sending content in the request body
@Path("/patient-set/{patientSetCollId}")
@Consumes(Array(MediaType.APPLICATION_XML))
def readPdo(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("patientSetCollId") patientSetCollId: String,
optionsXml: String,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
import XML.loadString
performAndSerialize(_.readPdo(ReadPdoRequest(projectId, waitTime, authorization, patientSetCollId, loadString(optionsXml)), shouldBroadcast))
}
@GET
@Path("/queries/{queryId}")
def readQueryDefinition(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") queryId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.readQueryDefinition(ReadQueryDefinitionRequest(projectId, waitTime, authorization, queryId), shouldBroadcast))
}
@DELETE
@Path("/queries/{queryId}")
def deleteQuery(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") queryId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.deleteQuery(DeleteQueryRequest(projectId, waitTime, authorization, queryId), shouldBroadcast))
}
@POST
@Path("/queries/{queryId}/name")
@Consumes(Array(MediaType.TEXT_PLAIN))
def renameQuery(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") queryId: Long,
queryName: String,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.renameQuery(RenameQueryRequest(projectId, waitTime, authorization, queryId, queryName), shouldBroadcast))
}
@GET
@Path("/queries/{queryId}/results")
@Consumes(Array(MediaType.TEXT_PLAIN))
def readQueryResults(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@PathParam("queryId") queryId: Long,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean): String = {
performAndSerialize(_.readQueryResult(ReadQueryResultRequest(projectId, waitTime, authorization, queryId), shouldBroadcast))
}
@POST
@Path("/queries/translated")
@Consumes(Array(MediaType.APPLICATION_XML))
def readTranslatedQueryDefinition(
@HeaderParam("projectId") projectId: String,
//authorization will be constructed by JAXRS using the String value of the 'Authorization' header
@HeaderParam("Authorization") authorization: AuthenticationInfo,
@HeaderParam("shouldBroadcast") shouldBroadcast: Boolean,
queryDefinitionXml: String): String = {
val queryDef = QueryDefinition.fromXml(queryDefinitionXml).get
//NB: Create the RunQueryRequest with a dummy networkQueryId of '-1';
//this will be filled in with an appropriately-generated value by the ShrineRequestHandler
performAndSerialize(_.readTranslatedQueryDefinition(ReadTranslatedQueryDefinitionRequest(authorization, waitTime, queryDef), shouldBroadcast))
}
private def performAndSerialize[R <: BaseShrineResponse](op: ShrineRequestHandler => R): String = {
op(shrineRequestHandler).toXmlString
}
}
//NB: extends ShrineRequestHandler => ShrineResource for smoother testing syntax
object ShrineResource extends (ShrineRequestHandler => ShrineResource) {
import scala.concurrent.duration._
val waitTime = 10.seconds
}