Skip to content

Commit

Permalink
ENT-1906: Trivial tweaks to DJVM code. (corda#3890)
Browse files Browse the repository at this point in the history
* Trivial tweaks to DJVM code.
  - Use ASM Type.getInternalName()
  - Use @JvmDefault annotation
  - Declare test base class as abstract
  - Ensure test Log4J configuration has precedence
  - Replace assert() with require()
  - Replace simple lambdas with function references
* Publish corda-djvm artifact.
* Migrate Utilities class into the CLI tool.
* Configure unit tests for console logging.
  • Loading branch information
chrisr3 authored Sep 5, 2018
1 parent a7f9320 commit 5b255c8
Show file tree
Hide file tree
Showing 22 changed files with 158 additions and 185 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ bintrayConfig {
'corda-rpc',
'corda-core',
'corda-core-deterministic',
'corda-djvm',
'corda',
'corda-finance',
'corda-node',
Expand Down
22 changes: 15 additions & 7 deletions djvm/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
plugins {
id 'com.github.johnrengelman.shadow' version '2.0.4'
}
apply plugin: 'net.corda.plugins.publish-utils'
apply plugin: 'com.jfrog.artifactory'

description 'Corda deterministic JVM sandbox'

ext {
// Shaded version of ASM to avoid conflict with root project.
Expand Down Expand Up @@ -30,8 +34,8 @@ dependencies {
jar.enabled = false

shadowJar {
baseName = "djvm"
classifier = ""
baseName 'corda-djvm'
classifier ''
dependencies {
exclude(dependency('com.jcabi:.*:.*'))
exclude(dependency('org.apache.*:.*:.*'))
Expand All @@ -40,10 +44,14 @@ shadowJar {
exclude(dependency('io.github.lukehutch:.*:.*'))
}
relocate 'org.objectweb.asm', 'djvm.org.objectweb.asm'
artifacts {
shadow(tasks.shadowJar.archivePath) {
builtBy shadowJar
}
}
}
assemble.dependsOn shadowJar

artifacts {
publish shadowJar
}

publish {
disableDefaultJar true
name shadowJar.baseName
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package net.corda.djvm.tools.cli

import net.corda.djvm.tools.Utilities.createCodePath
import net.corda.djvm.tools.Utilities.getFileNames
import net.corda.djvm.tools.Utilities.jarPath
import picocli.CommandLine.Command
import picocli.CommandLine.Parameters
import java.nio.file.Path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ import net.corda.djvm.execution.*
import net.corda.djvm.references.ClassModule
import net.corda.djvm.source.ClassSource
import net.corda.djvm.source.SourceClassLoader
import net.corda.djvm.tools.Utilities.find
import net.corda.djvm.tools.Utilities.onEmpty
import net.corda.djvm.tools.Utilities.userClassPath
import net.corda.djvm.utilities.Discovery
import djvm.org.objectweb.asm.ClassReader
import picocli.CommandLine.Option
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package net.corda.djvm.tools.cli

import net.corda.djvm.source.ClassSource
import net.corda.djvm.tools.Utilities.createCodePath
import picocli.CommandLine.Command
import picocli.CommandLine.Parameters
import java.nio.file.Files
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package net.corda.djvm.tools.cli

import net.corda.djvm.tools.Utilities.baseName
import net.corda.djvm.tools.Utilities.createCodePath
import net.corda.djvm.tools.Utilities.getFiles
import net.corda.djvm.tools.Utilities.openOptions
import picocli.CommandLine.*
import java.nio.file.Files
import java.nio.file.Path
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package net.corda.djvm.tools.cli

import net.corda.djvm.tools.Utilities.workingDirectory
import picocli.CommandLine.Command
import java.nio.file.Files

Expand Down
104 changes: 104 additions & 0 deletions djvm/cli/src/main/kotlin/net/corda/djvm/tools/cli/Utilities.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
@file:JvmName("Utilities")
package net.corda.djvm.tools.cli

import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
import java.lang.reflect.Modifier
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.StandardOpenOption

/**
* Get the expanded file name of each path in the provided array.
*/
fun Array<Path>?.getFiles(map: (Path) -> Path = { it }) = (this ?: emptyArray()).map {
val pathString = it.toString()
val path = map(it)
when {
'/' in pathString || '\\' in pathString ->
throw Exception("Please provide a pathless file name")
pathString.endsWith(".java", true) -> path
else -> Paths.get("$path.java")
}
}

/**
* Get the string representation of each expanded file name in the provided array.
*/
fun Array<Path>?.getFileNames(map: (Path) -> Path = { it }) = this.getFiles(map).map {
it.toString()
}.toTypedArray()

/**
* Execute inlined action if the collection is empty.
*/
inline fun <T> List<T>.onEmpty(action: () -> Unit): List<T> {
if (!this.any()) {
action()
}
return this
}

/**
* Execute inlined action if the array is empty.
*/
inline fun <reified T> Array<T>?.onEmpty(action: () -> Unit): Array<T> {
return (this ?: emptyArray()).toList().onEmpty(action).toTypedArray()
}

/**
* Derive the set of [StandardOpenOption]'s to use for a file operation.
*/
fun openOptions(force: Boolean) = if (force) {
arrayOf(StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)
} else {
arrayOf(StandardOpenOption.CREATE_NEW)
}

/**
* Get the path of where any generated code will be placed. Create the directory if it does not exist.
*/
fun createCodePath(): Path {
return Paths.get("tmp", "net", "corda", "djvm").let {
Files.createDirectories(it)
}
}

/**
* Return the base name of a file (i.e., its name without extension)
*/
val Path.baseName: String
get() = this.fileName.toString()
.replaceAfterLast('.', "")
.removeSuffix(".")

/**
* The path of the executing JAR.
*/
val jarPath: String = object {}.javaClass.protectionDomain.codeSource.location.toURI().path


/**
* The path of the current working directory.
*/
val workingDirectory: Path = Paths.get(System.getProperty("user.dir"))

/**
* The class path for the current execution context.
*/
val userClassPath: String = System.getProperty("java.class.path")

/**
* Get a reference of each concrete class that implements interface or class [T].
*/
inline fun <reified T> find(scanSpec: String = "net/corda/djvm"): List<Class<*>> {
val references = mutableListOf<Class<*>>()
FastClasspathScanner(scanSpec)
.matchClassesImplementing(T::class.java) { clazz ->
if (!Modifier.isAbstract(clazz.modifiers) && !Modifier.isStatic(clazz.modifiers)) {
references.add(clazz)
}
}
.scan()
return references
}
1 change: 1 addition & 0 deletions djvm/src/main/kotlin/net/corda/djvm/code/Emitter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface Emitter {
/**
* Indication of whether or not the emitter performs instrumentation for tracing inside the sandbox.
*/
@JvmDefault
val isTracer: Boolean
get() = false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ interface MemberInformation {
val className: String
val memberName: String
val signature: String
@JvmDefault
val reference: String get() = "$className.$memberName:$signature"
}
4 changes: 3 additions & 1 deletion djvm/src/main/kotlin/net/corda/djvm/rewiring/LoadedClass.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.corda.djvm.rewiring

import org.objectweb.asm.Type

/**
* A class or interface running in a Java application, together with its raw byte code representation and all references
* made from within the type.
Expand All @@ -16,7 +18,7 @@ class LoadedClass(
* The name of the loaded type.
*/
val name: String
get() = type.name.replace('.', '/')
get() = Type.getInternalName(type)

override fun toString(): String {
return "Class(type=$name, size=${byteCode.bytes.size}, isModified=${byteCode.isModified})"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.ClassWriter.COMPUTE_FRAMES
import org.objectweb.asm.ClassWriter.COMPUTE_MAXS
import org.objectweb.asm.Type

/**
* Class writer for sandbox execution, with configurable a [classLoader] to ensure correct deduction of the used class
Expand Down Expand Up @@ -52,7 +53,7 @@ open class SandboxClassWriter(
do {
clazz = clazz.superclass
} while (!clazz.isAssignableFrom(class2))
clazz.name.replace('.', '/')
Type.getInternalName(clazz)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ open class SourceClassLoader(
when {
!Files.exists(it) -> throw FileNotFoundException("File not found; $it")
Files.isDirectory(it) -> {
listOf(it.toURL()) + Files.list(it).filter { isJarFile(it) }.map { it.toURL() }.toList()
listOf(it.toURL()) + Files.list(it).filter(::isJarFile).map { it.toURL() }.toList()
}
Files.isReadable(it) && isJarFile(it) -> listOf(it.toURL())
else -> throw IllegalArgumentException("Expected JAR or class file, but found $it")
Expand Down
114 changes: 0 additions & 114 deletions djvm/src/main/kotlin/net/corda/djvm/tools/Utilities.kt

This file was deleted.

3 changes: 2 additions & 1 deletion djvm/src/main/kotlin/net/corda/djvm/utilities/Discovery.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import java.lang.reflect.Modifier
* Find and instantiate types that implement a certain interface.
*/
object Discovery {
const val FORBIDDEN_CLASS_MASK = (Modifier.STATIC or Modifier.ABSTRACT)

/**
* Get an instance of each concrete class that implements interface or class [T].
Expand All @@ -15,7 +16,7 @@ object Discovery {
val instances = mutableListOf<T>()
FastClasspathScanner("net/corda/djvm")
.matchClassesImplementing(T::class.java) { clazz ->
if (!Modifier.isAbstract(clazz.modifiers) && !Modifier.isStatic(clazz.modifiers)) {
if (clazz.modifiers and FORBIDDEN_CLASS_MASK == 0) {
try {
instances.add(clazz.newInstance())
} catch (exception: Throwable) {
Expand Down
2 changes: 1 addition & 1 deletion djvm/src/test/kotlin/foo/bar/sandbox/StrictFloat.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class StrictFloat : Callable {
override fun call() {
val d = java.lang.Double.MIN_VALUE
val x = d / 2 * 2
assert(x.toString() == "0.0")
require(x.toString() == "0.0")
}
}

Loading

0 comments on commit 5b255c8

Please sign in to comment.