diff --git a/build.gradle.kts b/build.gradle.kts index f29110e..e273249 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,6 +21,8 @@ dependencies { implementation(kotlin("stdlib-jdk8")) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5") implementation("org.apache.activemq:activemq-client:5.15.12") + implementation("org.glassfish.jersey.containers:jersey-container-grizzly2-http:2.25") + implementation("org.glassfish.jersey.media:jersey-media-json-jackson:2.25") testCompile("junit", "junit", "4.12") detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.7.0-beta2") } diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index 8a9ad40..3b05b45 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -263,7 +263,7 @@ formatting: active: true autoCorrect: true NoSemicolons: - active: true + active: false autoCorrect: true NoTrailingSpaces: active: true diff --git a/src/main/kotlin/drills/drill08/exercise1/Client.kt b/src/main/kotlin/drills/drill08/exercise1/Client.kt new file mode 100644 index 0000000..478afcc --- /dev/null +++ b/src/main/kotlin/drills/drill08/exercise1/Client.kt @@ -0,0 +1,11 @@ +package drills.drill08.exercise1 + +import util.jms.replicatedobject.ReplicatedObjectFactory + +fun main() { + val factory = ReplicatedObjectFactory(Finder::class.java) + val finder = factory.create("finder") + + println("ciao: ${finder.find("ciao")}") + println("ciao!: ${finder.find("ciao!")}") +} diff --git a/src/main/kotlin/drills/drill08/exercise1/Finder.kt b/src/main/kotlin/drills/drill08/exercise1/Finder.kt new file mode 100644 index 0000000..80fe383 --- /dev/null +++ b/src/main/kotlin/drills/drill08/exercise1/Finder.kt @@ -0,0 +1,11 @@ +package drills.drill08.exercise1 + +interface Finder { + fun find(str: String): Boolean +} + +class FakeFinder : Finder { + override fun find(str: String): Boolean { + return str.length % 2 == 0 + } +} diff --git a/src/main/kotlin/drills/drill08/exercise1/Server.kt b/src/main/kotlin/drills/drill08/exercise1/Server.kt new file mode 100644 index 0000000..a0b5da6 --- /dev/null +++ b/src/main/kotlin/drills/drill08/exercise1/Server.kt @@ -0,0 +1,10 @@ +package drills.drill08.exercise1 + +import util.jms.replicatedobject.ReplicatedObject + +fun main() { + val finder: Finder = FakeFinder() + + ReplicatedObject(finder, "finder") + .start() +} diff --git a/src/main/kotlin/drills/drill08/exercise2/Client.kt b/src/main/kotlin/drills/drill08/exercise2/Client.kt new file mode 100644 index 0000000..10ebc6d --- /dev/null +++ b/src/main/kotlin/drills/drill08/exercise2/Client.kt @@ -0,0 +1,27 @@ +package drills.drill08.exercise2 + +import util.rmi.Client +import kotlin.time.ExperimentalTime +import kotlin.time.measureTime + +@ExperimentalTime +fun main() { + Client(clientHandler).start() +} + +@ExperimentalTime +val clientHandler = { + val finder = Client.lookup("finder") as Finder + + val workerNumber = 4 + + val workers = Array(workerNumber) { Worker(finder) } + + val elapsed = measureTime { + workers.forEach { it.start() } + workers.forEach { it.join() } + } + + println("Total elapsed time: $elapsed") + println("Throughput: ${(workerNumber * Worker.REQUEST_NUMBER) / elapsed.inSeconds} req/s") +} diff --git a/src/main/kotlin/drills/drill08/exercise2/Finder.kt b/src/main/kotlin/drills/drill08/exercise2/Finder.kt new file mode 100644 index 0000000..d338e7e --- /dev/null +++ b/src/main/kotlin/drills/drill08/exercise2/Finder.kt @@ -0,0 +1,18 @@ +package drills.drill08.exercise2 + +import java.rmi.Remote +import java.rmi.RemoteException +import java.rmi.server.UnicastRemoteObject + +interface Finder : Remote { + @Throws(RemoteException::class) + fun find(str: String): Boolean +} + +class FakeFinder : UnicastRemoteObject(), Finder { + override fun find(str: String): Boolean { + println(str) + for (i in 0 until 100000000L); + return str.length % 2 == 0 + } +} diff --git a/src/main/kotlin/drills/drill08/exercise2/Server.kt b/src/main/kotlin/drills/drill08/exercise2/Server.kt new file mode 100644 index 0000000..6766e07 --- /dev/null +++ b/src/main/kotlin/drills/drill08/exercise2/Server.kt @@ -0,0 +1,10 @@ +package drills.drill08.exercise2 + +import util.rmi.Server + +fun main() { + Server { + val finder: Finder = FakeFinder() + Server.bind(finder, "finder") + }.start() +} diff --git a/src/main/kotlin/drills/drill08/exercise2/Worker.kt b/src/main/kotlin/drills/drill08/exercise2/Worker.kt new file mode 100644 index 0000000..3995a9b --- /dev/null +++ b/src/main/kotlin/drills/drill08/exercise2/Worker.kt @@ -0,0 +1,22 @@ +package drills.drill08.exercise2 + +import kotlin.time.ExperimentalTime +import kotlin.time.measureTime + +class Worker(private val finder: Finder) : Thread() { + @ExperimentalTime + override fun run() { + val elapsed = measureTime { + repeat(REQUEST_NUMBER) { + finder.find("test-$it") + } + } + + println("Thread $this elapsed: $elapsed") + println("Thread $this mean time for request: ${elapsed / REQUEST_NUMBER}") + } + + companion object { + const val REQUEST_NUMBER = 60 + } +} diff --git a/src/main/kotlin/drills/drill08/exercise3/Client.kt b/src/main/kotlin/drills/drill08/exercise3/Client.kt new file mode 100644 index 0000000..ae264a4 --- /dev/null +++ b/src/main/kotlin/drills/drill08/exercise3/Client.kt @@ -0,0 +1,29 @@ +package drills.drill08.exercise3 + +import drills.drill08.exercise2.Finder +import drills.drill08.exercise2.Worker +import util.rmi.Client +import kotlin.time.ExperimentalTime +import kotlin.time.measureTime + +@ExperimentalTime +fun main() { + Client(clientHandler).start() +} + +@ExperimentalTime +val clientHandler = { + val finder = Client.lookup("finder") as Finder + + val workerNumber = 4 + + val workers = Array(workerNumber) { Worker(finder) } + + val elapsed = measureTime { + workers.forEach { it.start() } + workers.forEach { it.join() } + } + + println("Total elapsed time: $elapsed") + println("Throughput: ${(workerNumber * Worker.REQUEST_NUMBER) / elapsed.inSeconds} req/s") +} diff --git a/src/main/kotlin/drills/drill08/exercise3/ReplicatedFinder.kt b/src/main/kotlin/drills/drill08/exercise3/ReplicatedFinder.kt new file mode 100644 index 0000000..5d202c5 --- /dev/null +++ b/src/main/kotlin/drills/drill08/exercise3/ReplicatedFinder.kt @@ -0,0 +1,9 @@ +package drills.drill08.exercise3 + +import drills.drill08.exercise2.FakeFinder +import util.jms.replicatedobject.ReplicatedObject + +fun main() { + ReplicatedObject(FakeFinder(), "finder") + .start() +} diff --git a/src/main/kotlin/drills/drill08/exercise3/Server.kt b/src/main/kotlin/drills/drill08/exercise3/Server.kt new file mode 100644 index 0000000..63bd96c --- /dev/null +++ b/src/main/kotlin/drills/drill08/exercise3/Server.kt @@ -0,0 +1,21 @@ +package drills.drill08.exercise3 + +import drills.drill08.exercise2.Finder +import util.jms.replicatedobject.ReplicatedObjectFactory +import util.rmi.Server +import java.rmi.server.UnicastRemoteObject + +fun main() { + Server { + val finder = FinderProxy() + Server.bind(finder, "finder") + }.start() +} + +class FinderProxy : Finder, UnicastRemoteObject() { + private val finder = ReplicatedObjectFactory(Finder::class.java) + .create("finder") + override fun find(str: String): Boolean { + return finder.find(str) + } +} diff --git a/src/main/kotlin/drills/drill08/exercise4/SearchService.kt b/src/main/kotlin/drills/drill08/exercise4/SearchService.kt new file mode 100644 index 0000000..833150a --- /dev/null +++ b/src/main/kotlin/drills/drill08/exercise4/SearchService.kt @@ -0,0 +1,22 @@ +package drills.drill08.exercise4 + +import drills.drill08.exercise2.Finder +import util.jms.replicatedobject.ReplicatedObjectFactory +import javax.ws.rs.Consumes +import javax.ws.rs.GET +import javax.ws.rs.Path +import javax.ws.rs.Produces +import javax.ws.rs.QueryParam +import javax.ws.rs.core.MediaType + +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Path("/search") +class SearchService { + private val finder = ReplicatedObjectFactory(Finder::class.java).create("finder") + + @GET + fun search(@QueryParam("str") str: String): Boolean { + return finder.find(str) + } +} diff --git a/src/main/kotlin/drills/drill08/exercise4/Server.kt b/src/main/kotlin/drills/drill08/exercise4/Server.kt new file mode 100644 index 0000000..b6b0663 --- /dev/null +++ b/src/main/kotlin/drills/drill08/exercise4/Server.kt @@ -0,0 +1,18 @@ +package drills.drill08.exercise4 + +import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory +import org.glassfish.jersey.server.ResourceConfig +import javax.ws.rs.core.UriBuilder + +fun main() { + val uri = UriBuilder + .fromUri("http://localhost/rest") + .port(8484) + .build() + + val resConfig = ResourceConfig().register(SearchService()) + val server = GrizzlyHttpServerFactory.createHttpServer(uri, resConfig) + server.start() + + while (server.isStarted); +} diff --git a/src/main/kotlin/util/jms/replicatedobject/Call.kt b/src/main/kotlin/util/jms/replicatedobject/Call.kt new file mode 100644 index 0000000..62aed80 --- /dev/null +++ b/src/main/kotlin/util/jms/replicatedobject/Call.kt @@ -0,0 +1,17 @@ +package util.jms.replicatedobject + +import java.io.Serializable + +data class Call( + val methodName: String, + val args: Array +) : Serializable { + fun execOn(target: Any): Any { + val method = target::class.java.getMethod( + methodName, + *args.map { it::class.java }.toTypedArray() + ) + + return method.invoke(target, *args) + } +} diff --git a/src/main/kotlin/util/jms/replicatedobject/ReplicatedObject.kt b/src/main/kotlin/util/jms/replicatedobject/ReplicatedObject.kt new file mode 100644 index 0000000..2a4702b --- /dev/null +++ b/src/main/kotlin/util/jms/replicatedobject/ReplicatedObject.kt @@ -0,0 +1,24 @@ +package util.jms.replicatedobject + +import util.jms.replier.ActiveMQReplier +import java.io.Serializable +import javax.jms.ObjectMessage + +class ReplicatedObject( + private val target: T, + queueName: String, + shared: Boolean = false +) { + private val replier = ActiveMQReplier(queueName, shared) + + init { + replier.onRequest { + val call = (it as ObjectMessage).`object` as Call + replier.createObjectMessage(call.execOn(target) as Serializable) + } + } + + fun start() { + replier.start() + } +} diff --git a/src/main/kotlin/util/jms/replicatedobject/ReplicatedObjectFactory.kt b/src/main/kotlin/util/jms/replicatedobject/ReplicatedObjectFactory.kt new file mode 100644 index 0000000..850f415 --- /dev/null +++ b/src/main/kotlin/util/jms/replicatedobject/ReplicatedObjectFactory.kt @@ -0,0 +1,16 @@ +package util.jms.replicatedobject + +import util.jms.requestor.ActiveMQRequestor +import java.lang.reflect.Proxy + +class ReplicatedObjectFactory(private val classType: Class) { + fun create(queueName: String, shared: Boolean = false): T { + val requestor = ActiveMQRequestor(queueName, shared) + + return Proxy.newProxyInstance( + this::class.java.classLoader, + arrayOf(classType), + ReplicatedObjectHandler(requestor) + ) as T + } +} diff --git a/src/main/kotlin/util/jms/replicatedobject/ReplicatedObjectHandler.kt b/src/main/kotlin/util/jms/replicatedobject/ReplicatedObjectHandler.kt new file mode 100644 index 0000000..c18448f --- /dev/null +++ b/src/main/kotlin/util/jms/replicatedobject/ReplicatedObjectHandler.kt @@ -0,0 +1,18 @@ +package util.jms.replicatedobject + +import util.jms.requestor.Requestor +import java.lang.reflect.InvocationHandler +import java.lang.reflect.Method +import javax.jms.ObjectMessage + +class ReplicatedObjectHandler( + private val requestor: Requestor +) : InvocationHandler { + override fun invoke(p0: Any, p1: Method, p2: Array): Any { + val call = Call(p1.name, p2) + + val msg = requestor.createObjectMessage(call) + + return (requestor.request(msg) as ObjectMessage).`object` + } +}