Skip to content

Commit

Permalink
spline #684 refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
wajda committed Sep 14, 2020
1 parent 021f28e commit 5a52371
Show file tree
Hide file tree
Showing 10 changed files with 230 additions and 127 deletions.
12 changes: 12 additions & 0 deletions build/parent-pom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,18 @@
<version>2.6</version>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.12</version>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.10</version>
</dependency>

<!-- Spring framework -->

<dependency>
Expand Down
29 changes: 19 additions & 10 deletions commons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
~ limitations under the License.
-->

<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">
<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">
<modelVersion>4.0.0</modelVersion>

<parent>
Expand Down Expand Up @@ -51,28 +52,36 @@
<artifactId>slf4s-api_${scala.compat.version}</artifactId>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>

<!-- only for za.co.absa.spline.webmvc package -->

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>

<!-- test scope -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2020 ABSA Group Limited
*
* 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 za.co.absa.spline.common.rest

import org.apache.http.HttpException

class HttpStatusException(val status: Int, message: String) extends HttpException(message)
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright 2020 ABSA Group Limited
*
* 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 za.co.absa.spline.common.rest

import java.net.URI

import org.apache.commons.io.IOUtils
import org.apache.http.auth.Credentials
import org.apache.http.client.methods.{HttpDelete, HttpGet, HttpPost, HttpRequestBase}
import org.apache.http.entity.StringEntity
import org.apache.http.impl.auth.BasicScheme
import org.apache.http.impl.client.HttpClients
import za.co.absa.commons.lang.ARM
import za.co.absa.commons.lang.ARM.managed

import scala.concurrent.{ExecutionContext, Future}

class RESTClient(uri: URI, maybeCredentials: Option[Credentials]) {
@throws[HttpStatusException]
def get(path: String): Future[String] = execHttp {
baseUri => new HttpGet(s"$baseUri/$path")
}

@throws[HttpStatusException]
def delete(path: String)(implicit ec: ExecutionContext): Future[Unit] = execHttp {
baseUri => new HttpDelete(s"$baseUri/$path")
}.map(_ => {})

@throws[HttpStatusException]
def post(path: String, body: String)(implicit ec: ExecutionContext): Future[Unit] = execHttp {
baseUri =>
new HttpPost(s"$baseUri/$path") {
setEntity(new StringEntity(body))
}
}.map(_ => {})

@throws[HttpStatusException]
private def execHttp(method: URI => HttpRequestBase): Future[String] = {
val request = {
val req = method(uri)
maybeCredentials.foreach(credentials => {
val authHeader = new BasicScheme().authenticate(credentials, req, null)
req.addHeader(authHeader)
})
req
}

val (respStatusLine, respBody) =
for {
httpClient <- managed(HttpClients.createDefault)
response <- managed(httpClient.execute(request))
} yield {
val maybeBody = Option(response.getEntity)
.map(e => {
val encoding = Option(e.getContentEncoding).map(_.getValue).getOrElse("UTF-8")
ARM.using(e.getContent) {
inputStream =>
IOUtils.toString(inputStream, encoding)
}
})
(response.getStatusLine, maybeBody.orNull)
}

respStatusLine.getStatusCode match {
case 200 | 201 | 204 =>
Future.successful(respBody)
case _ =>
throw new HttpStatusException(respStatusLine.getStatusCode, s"ArangoDB response: $respStatusLine. $respBody")
}
}
}
1 change: 0 additions & 1 deletion persistence/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.10</version>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2020 ABSA Group Limited
*
* 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.arangodb.async.internal

import com.arangodb.internal.velocystream.VstCommunication
import za.co.absa.commons.reflect.ReflectionUtils

object ArangoExecutorAsyncExtractor {
private final val CommunicationField = "communication"

def unapply(executor: ArangoExecutorAsync): Option[VstCommunication[_, _]] = {
Option(
ReflectionUtils.extractFieldValue(executor, CommunicationField)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,12 @@ package com.arangodb.internal {
import java.net.URI

import com.arangodb.async.ArangoDatabaseAsync
import com.arangodb.async.internal.ArangoExecutorAsync
import com.arangodb.async.internal.velocystream.VstCommunicationAsync
import com.arangodb.internal.velocystream.ConnectionParams
import org.apache.commons.io.IOUtils
import org.apache.http.HttpException
import com.arangodb.async.internal.{ArangoExecutorAsync, ArangoExecutorAsyncExtractor}
import com.arangodb.internal.velocystream.VstCommunicationExtractor
import org.apache.http.auth.UsernamePasswordCredentials
import org.apache.http.client.methods.{HttpDelete, HttpGet, HttpPost, HttpRequestBase}
import org.apache.http.entity.StringEntity
import org.apache.http.impl.auth.BasicScheme
import org.apache.http.impl.client.HttpClients
import org.json4s._
import org.json4s.jackson.JsonMethods._
import za.co.absa.commons.lang.ARM
import za.co.absa.commons.lang.ARM.managed
import za.co.absa.commons.reflect.ReflectionUtils
import za.co.absa.spline.common.rest.{HttpStatusException, RESTClient}

import scala.concurrent.{ExecutionContext, Future}

Expand All @@ -43,16 +34,26 @@ package com.arangodb.internal {
*/
object ArangoDatabaseImplicits {

class HttpStatusException(val status: Int, message: String) extends HttpException(message)

implicit class InternalArangoDatabaseOps(val db: ArangoDatabaseAsync) extends AnyVal {

private def restClient = {
val asyncExecutable = db.asInstanceOf[ArangoExecuteable[ArangoExecutorAsync]]
val ArangoExecutorAsyncExtractor(vstComm) = asyncExecutable.executor
val VstCommunicationExtractor(hostDescription, user, password) = vstComm
val host = hostDescription.getHost
val port = hostDescription.getPort
val maybeCredentials = Option(user).map(user => new UsernamePasswordCredentials(user, password))

new RESTClient(new URI(s"http://$host:$port/_db/${db.name}"), maybeCredentials)
}


/**
* @see [[https://github.com/arangodb/arangodb-java-driver/issues/353]]
*/
def adminExecute(script: String)(implicit ec: ExecutionContext): Future[Unit] =
try {
post("_admin/execute", script)
restClient.post("_admin/execute", script)
}
catch {
case e: HttpStatusException if e.status == 404 =>
Expand All @@ -66,77 +67,18 @@ package com.arangodb.internal {
* @see [[https://github.com/arangodb/arangodb-java-driver/issues/353]]
*/
def foxxInstall(mountPrefix: String, script: String)(implicit ec: ExecutionContext): Future[Unit] =
post(s"_api/foxx?mount=$mountPrefix", script)
restClient.post(s"_api/foxx?mount=$mountPrefix", script)

/**
* @see [[https://github.com/arangodb/arangodb-java-driver/issues/353]]
*/
def foxxUninstall(mountPrefix: String)(implicit ec: ExecutionContext): Future[Unit] =
delete(s"_api/foxx/service?mount=$mountPrefix")
restClient.delete(s"_api/foxx/service?mount=$mountPrefix")

def foxxList()(implicit ec: ExecutionContext): Future[Seq[Map[String, Any]]] =
get(s"_api/foxx").map(str =>
restClient.get(s"_api/foxx").map(str =>
parse(str).extract(DefaultFormats, manifest[Seq[Map[String, Any]]])
)

@throws[HttpStatusException]
private def get(path: String): Future[String] = execHttp {
baseUri => new HttpGet(s"$baseUri/$path")
}

@throws[HttpStatusException]
private def delete(path: String)(implicit ec: ExecutionContext): Future[Unit] = execHttp {
baseUri => new HttpDelete(s"$baseUri/$path")
}.map(_ => {})

@throws[HttpStatusException]
private def post(path: String, body: String)(implicit ec: ExecutionContext): Future[Unit] = execHttp {
baseUri =>
new HttpPost(s"$baseUri/$path") {
setEntity(new StringEntity(body))
}
}.map(_ => {})

@throws[HttpStatusException]
private def execHttp(method: URI => HttpRequestBase): Future[String] = {
val executor = db.asInstanceOf[ArangoExecuteable[_ <: ArangoExecutorAsync]].executor
val dbName = db.name
val comm = ReflectionUtils.extractFieldValue[VstCommunicationAsync](executor, "communication")
val ConnectionParams(host, port, maybeUser, maybePassword) = comm

val request = {
val req = method(new URI(s"http://$host:$port/_db/$dbName"))
maybeUser.foreach(user => {
val credentials = new UsernamePasswordCredentials(user, maybePassword.orNull)
val authHeader = new BasicScheme().authenticate(credentials, req, null)
req.addHeader(authHeader)
})
req
}

val (respStatusLine, respBody) =
for {
httpClient <- managed(HttpClients.createDefault)
response <- managed(httpClient.execute(request))
} yield {
val maybeBody = Option(response.getEntity)
.map(e => {
val encoding = Option(e.getContentEncoding).map(_.getValue).getOrElse("UTF-8")
ARM.using(e.getContent) {
inputStream =>
IOUtils.toString(inputStream, encoding)
}
})
(response.getStatusLine, maybeBody.orNull)
}

respStatusLine.getStatusCode match {
case 200 | 201 | 204 =>
Future.successful(respBody)
case _ =>
throw new HttpStatusException(respStatusLine.getStatusCode, s"ArangoDB response: $respStatusLine. $respBody")
}
}
}

}
Expand Down
Loading

0 comments on commit 5a52371

Please sign in to comment.