diff --git a/adapter/adapter-service/src/main/scala/net/shrine/adapter/Adapter.scala b/adapter/adapter-service/src/main/scala/net/shrine/adapter/Adapter.scala
index 698b978e1..2388a5a27 100644
--- a/adapter/adapter-service/src/main/scala/net/shrine/adapter/Adapter.scala
+++ b/adapter/adapter-service/src/main/scala/net/shrine/adapter/Adapter.scala
@@ -1,77 +1,88 @@
package net.shrine.adapter
+import java.sql.SQLSyntaxErrorException
+
import net.shrine.log.Loggable
import net.shrine.problem.{Problem, ProblemNotYetEncoded, LoggingProblemHandler, ProblemSources, AbstractProblem}
import net.shrine.protocol.{ShrineRequest, BroadcastMessage, ErrorResponse, BaseShrineResponse, AuthenticationInfo}
/**
* @author Bill Simons
* @since 4/8/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
*/
abstract class Adapter extends Loggable {
final def perform(message: BroadcastMessage): BaseShrineResponse = {
def problemToErrorResponse(problem:Problem):ErrorResponse = {
LoggingProblemHandler.handleProblem(problem)
ErrorResponse(problem)
}
val shrineResponse = try {
processRequest(message)
} catch {
case e: AdapterLockoutException => problemToErrorResponse(AdapterLockout(message.request.authn,e))
case e @ CrcInvocationException(invokedCrcUrl, request, cause) => problemToErrorResponse(CrcCouldNotBeInvoked(invokedCrcUrl,request,e))
case e: AdapterMappingException => problemToErrorResponse(AdapterMappingProblem(e))
+ case e: SQLSyntaxErrorException => problemToErrorResponse(AdapterDatabaseProblem(e))
+
//noinspection RedundantBlock
case e: Exception => {
val summary = if(message == null) "Unknown problem in Adapter.perform with null BroadcastMessage"
else s"Unexpected exception in Adapter"
problemToErrorResponse(ProblemNotYetEncoded(summary,e))
}
}
shrineResponse
}
protected[adapter] def processRequest(message: BroadcastMessage): BaseShrineResponse
//NOOP, may be overridden by subclasses
def shutdown(): Unit = ()
}
case class AdapterLockout(authn:AuthenticationInfo,x:AdapterLockoutException) extends AbstractProblem(ProblemSources.Adapter) {
override val throwable = Some(x)
override val summary: String = s"User '${authn.domain}:${authn.username}' locked out."
override val description:String = s"User '${authn.domain}:${authn.username}' has run too many queries that produce the same result at ${x.url} ."
}
case class CrcCouldNotBeInvoked(crcUrl:String,request:ShrineRequest,x:CrcInvocationException) extends AbstractProblem(ProblemSources.Adapter) {
override val throwable = Some(x)
override val summary: String = s"Error communicating with I2B2 CRC."
override val description: String = s"Error invoking the CRC at '$crcUrl' with a ${request.getClass.getSimpleName} due to ${throwable.get}."
override val detailsXml =
Request is {request}
{throwableDetail.getOrElse("")}
}
case class AdapterMappingProblem(x:AdapterMappingException) extends AbstractProblem(ProblemSources.Adapter) {
override val throwable = Some(x)
override val summary: String = "Could not map query term(s)."
override val description = s"The Shrine Adapter on ${stamp.host.getHostName} cannot map this query to its local terms."
override val detailsXml =
Query Defitiontion is {x.runQueryRequest.queryDefinition}
RunQueryRequest is ${x.runQueryRequest.elideAuthenticationInfo}
{throwableDetail.getOrElse("")}
}
+
+case class AdapterDatabaseProblem(x:SQLSyntaxErrorException) extends AbstractProblem(ProblemSources.Adapter) {
+
+ override val throwable = Some(x)
+ override val summary: String = "Problem in an adapter database."
+ override val description = s"The Shrine Adapter on encountered a problem with a database."
+}
diff --git a/adapter/adapter-service/src/main/scala/net/shrine/adapter/CrcAdapter.scala b/adapter/adapter-service/src/main/scala/net/shrine/adapter/CrcAdapter.scala
index 89ffff9e0..1bf69342d 100644
--- a/adapter/adapter-service/src/main/scala/net/shrine/adapter/CrcAdapter.scala
+++ b/adapter/adapter-service/src/main/scala/net/shrine/adapter/CrcAdapter.scala
@@ -1,115 +1,104 @@
package net.shrine.adapter
import net.shrine.problem.{ProblemSources, AbstractProblem}
import org.xml.sax.SAXParseException
import scala.xml.NodeSeq
import scala.xml.XML
import net.shrine.protocol.{HiveCredentials, AuthenticationInfo, BroadcastMessage, Credential, ShrineRequest, ShrineResponse, TranslatableRequest, BaseShrineRequest, ErrorResponse, BaseShrineResponse}
-import net.shrine.serialization.XmlMarshaller
-import net.shrine.client.HttpClient
import net.shrine.util.XmlDateHelper
import net.shrine.client.Poster
-import net.shrine.util.XmlUtil
-import net.shrine.client.HttpResponse
import scala.util.Try
import scala.util.control.NonFatal
/**
* @author Bill Simons
* @since 4/11/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
*/
abstract class CrcAdapter[T <: ShrineRequest, V <: ShrineResponse](
poster: Poster,
override protected val hiveCredentials: HiveCredentials) extends WithHiveCredentialsAdapter(hiveCredentials) {
protected def parseShrineResponse(nodeSeq: NodeSeq): ShrineResponse
private[adapter] def parseShrineErrorResponseWithFallback(xmlResponseFromCrc: String): ShrineResponse = {
//NB: See https://open.med.harvard.edu/jira/browse/SHRINE-534
//NB: https://open.med.harvard.edu/jira/browse/SHRINE-745
val shrineResponseAttempt = for {
crcXml <- Try(XML.loadString(xmlResponseFromCrc))
shrineResponse <- Try(parseShrineResponse(crcXml)).recover { case NonFatal(e) => ErrorResponse.fromI2b2(crcXml) }
} yield shrineResponse
shrineResponseAttempt.recover {
case saxx:SAXParseException => ErrorResponse(CannotParseXmlFromCrc(saxx,xmlResponseFromCrc))
case NonFatal(e) =>
error(s"Error parsing response from CRC: ", e)
ErrorResponse(ExceptionWhileLoadingCrcResponse(e,xmlResponseFromCrc))
}.get
}
case class CannotParseXmlFromCrc(saxx:SAXParseException,xmlResponseFromCrc: String) extends AbstractProblem(ProblemSources.Adapter) {
override val throwable = Some(saxx)
override val summary: String = "Could not parse response from CRC."
override val description:String = s"${saxx.getMessage} while parsing the response from the CRC."
override val detailsXml =
{throwableDetail.getOrElse("")}
Response is {xmlResponseFromCrc}
}
case class ExceptionWhileLoadingCrcResponse(t:Throwable,xmlResponseFromCrc: String) extends AbstractProblem(ProblemSources.Adapter) {
override val throwable = Some(t)
override val summary: String = "Unanticipated exception with response from CRC."
override val description:String = s"${t.getMessage} while parsing the response from the CRC."
override val detailsXml =
{throwableDetail.getOrElse("")}
Response is {xmlResponseFromCrc}
}
//NB: default is a noop; only RunQueryAdapter needs this for now
protected[adapter] def translateNetworkToLocal(request: T): T = request
protected[adapter] override def processRequest(message: BroadcastMessage): BaseShrineResponse = {
val i2b2Response = callCrc(translateRequest(message.request))
parseShrineErrorResponseWithFallback(i2b2Response)
}
protected def callCrc(request: ShrineRequest): String = {
- def prettyPrintXmlString(reqXml: String): Try[String] = Try {
- XmlUtil.prettyPrint(XML.loadString(reqXml))
- }
-
- def prettyPrintResponse(resp: HttpResponse): Try[HttpResponse] = {
- prettyPrintXmlString(resp.body).map(prettyPrintedXml => resp.copy(body = s"\r\n$prettyPrintedXml"))
- }
-
debug(s"Sending Shrine-formatted request to the CRC at '${poster.url}': $request")
val crcRequest = request.toI2b2String
val crcResponse = XmlDateHelper.time(s"Calling the CRC at '${poster.url}'")(debug(_)) {
//Wrap exceptions in a more descriptive form, to enable sending better error messages back to the legacy web client
try { poster.post(crcRequest) }
catch {
case NonFatal(e) => throw CrcInvocationException(poster.url, request, e)
}
}
crcResponse.body
}
private[adapter] def translateRequest(request: BaseShrineRequest): ShrineRequest = request match {
- case transReq: TranslatableRequest[T] => {
+ case transReq: TranslatableRequest[T] => //noinspection RedundantBlock
+ {
val HiveCredentials(domain, username, password, project) = hiveCredentials
- val authInfo = AuthenticationInfo(domain, username, Credential(password, false))
+ val authInfo = AuthenticationInfo(domain, username, Credential(password, isToken = false))
translateNetworkToLocal(transReq.withAuthn(authInfo).withProject(project).asRequest)
}
case req: ShrineRequest => req
case _ => throw new IllegalArgumentException(s"Unexpected request: $request")
}
}
\ No newline at end of file