mirror of
https://github.com/corda/corda.git
synced 2025-06-01 23:20:54 +00:00
CORDA-2696 eliminate duplicate class warnings
This commit is contained in:
parent
eb70fc9e6b
commit
4f7ea8cd52
@ -1,5 +1,6 @@
|
|||||||
package net.corda.core.internal.cordapp
|
package net.corda.core.internal.cordapp
|
||||||
|
|
||||||
|
import net.corda.core.contracts.Contract
|
||||||
import net.corda.core.cordapp.Cordapp
|
import net.corda.core.cordapp.Cordapp
|
||||||
import net.corda.core.internal.PLATFORM_VERSION
|
import net.corda.core.internal.PLATFORM_VERSION
|
||||||
import net.corda.core.internal.VisibleForTesting
|
import net.corda.core.internal.VisibleForTesting
|
||||||
@ -10,8 +11,10 @@ import java.util.concurrent.ConcurrentHashMap
|
|||||||
* Provides a way to acquire information about the calling CorDapp.
|
* Provides a way to acquire information about the calling CorDapp.
|
||||||
*/
|
*/
|
||||||
object CordappResolver {
|
object CordappResolver {
|
||||||
|
|
||||||
private val logger = loggerFor<CordappResolver>()
|
private val logger = loggerFor<CordappResolver>()
|
||||||
private val cordappClasses: ConcurrentHashMap<String, Set<Cordapp>> = ConcurrentHashMap()
|
private val cordappClasses: ConcurrentHashMap<String, Set<Cordapp>> = ConcurrentHashMap()
|
||||||
|
private val duplicateRegistrationFilter = DuplicateRegistrationFilter(setOf("org.jolokia", "org.json"))
|
||||||
|
|
||||||
// TODO Use the StackWalker API once we migrate to Java 9+
|
// TODO Use the StackWalker API once we migrate to Java 9+
|
||||||
private var cordappResolver: () -> Cordapp? = {
|
private var cordappResolver: () -> Cordapp? = {
|
||||||
@ -29,18 +32,26 @@ object CordappResolver {
|
|||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun register(cordapp: Cordapp) {
|
fun register(cordapp: Cordapp) {
|
||||||
cordapp.cordappClasses.forEach {
|
val existingClasses = cordappClasses.keys
|
||||||
val cordapps = cordappClasses[it]
|
val classesToRegister = cordapp.cordappClasses.toSet()
|
||||||
if (cordapps != null) {
|
val alreadyRegisteredClasses = existingClasses.intersect(classesToRegister)
|
||||||
// we do not register CorDapps that originate from the same file.
|
val notAlreadyRegisteredClasses = classesToRegister - alreadyRegisteredClasses
|
||||||
if (cordapps.none { it.jarHash == cordapp.jarHash }) {
|
|
||||||
logger.warn("More than one CorDapp registered for $it.")
|
notAlreadyRegisteredClasses.forEach { cordappClasses[it] = setOf(cordapp) }
|
||||||
cordappClasses[it] = cordappClasses[it]!! + cordapp
|
|
||||||
}
|
val toRegister = cordappClasses.entries.asSequence()
|
||||||
} else {
|
.filter { (className, _) -> className in alreadyRegisteredClasses}
|
||||||
cordappClasses[it] = setOf(cordapp)
|
.filter { (_, registeredCordapps) -> registeredCordapps.none { it.jarHash == cordapp.jarHash } }
|
||||||
|
.map { (className, registeredCordapps) -> className to registeredCordapps + cordapp }
|
||||||
|
.toMap()
|
||||||
|
|
||||||
|
for (className in toRegister.keys) {
|
||||||
|
if (duplicateRegistrationFilter.shouldNotify(className, cordapp::class.java.classLoader)) {
|
||||||
|
logger.warn("More than one CorDapp registered for $className.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cordappClasses.putAll(toRegister)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -82,3 +93,34 @@ object CordappResolver {
|
|||||||
cordappClasses.clear()
|
cordappClasses.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class DuplicateRegistrationFilter(private val ignoreList: Set<String>) {
|
||||||
|
|
||||||
|
private var alreadySeen: Set<String> = emptySet()
|
||||||
|
|
||||||
|
fun shouldNotify(className: String, classLoader: ClassLoader): Boolean {
|
||||||
|
if (className in alreadySeen) return false
|
||||||
|
alreadySeen += className
|
||||||
|
|
||||||
|
if (className.canBeIgnored) return false
|
||||||
|
return className.isContractClass(classLoader)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val String.canBeIgnored: Boolean get() = packagePrefixes.any { it in ignoreList }
|
||||||
|
private val String.packagePrefixes: Iterable<String> get() = Iterable { object : Iterator<String> {
|
||||||
|
|
||||||
|
private var index: Int = 0
|
||||||
|
private val nextIndex: Int get() = this@packagePrefixes.indexOf(".", index)
|
||||||
|
|
||||||
|
override fun hasNext(): Boolean = nextIndex > 0
|
||||||
|
|
||||||
|
override fun next(): String {
|
||||||
|
val nextSeparatorPosition = nextIndex
|
||||||
|
index = nextSeparatorPosition + 1
|
||||||
|
return this@packagePrefixes.substring(0, nextSeparatorPosition)
|
||||||
|
}
|
||||||
|
} }
|
||||||
|
|
||||||
|
private fun String.isContractClass(classLoader: ClassLoader): Boolean = Contract::class.java.isAssignableFrom(classLoader.loadClass(this))
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
package net.corda.core.internal.cordapp
|
||||||
|
|
||||||
|
import net.corda.core.contracts.Contract
|
||||||
|
import net.corda.core.transactions.LedgerTransaction
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class DuplicationRegistrationFilterTest {
|
||||||
|
|
||||||
|
private val classLoader = ClassLoader.getSystemClassLoader()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `ignores anything in the ignore list`() {
|
||||||
|
val filter = DuplicateRegistrationFilter(setOf("foo.bar", "foo.baz", "net.corda"))
|
||||||
|
|
||||||
|
assertFalse(filter.shouldNotify("foo.bar.A", classLoader))
|
||||||
|
assertFalse(filter.shouldNotify("foo.baz.xyzzy.B", classLoader))
|
||||||
|
assertFalse(filter.shouldNotify(ActuallyAContract::class.java.name, classLoader))
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotAContract
|
||||||
|
|
||||||
|
class ActuallyAContract : Contract {
|
||||||
|
override fun verify(tx: LedgerTransaction) = Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `ignores anything that isn't a contract`() {
|
||||||
|
val filter = DuplicateRegistrationFilter(setOf("foo.bar", "foo.baz"))
|
||||||
|
|
||||||
|
assertFalse(filter.shouldNotify(NotAContract::class.java.name, classLoader))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `notifies anything that is a contract`() {
|
||||||
|
val filter = DuplicateRegistrationFilter(setOf("foo.bar", "foo.baz"))
|
||||||
|
|
||||||
|
assertTrue(filter.shouldNotify(ActuallyAContract::class.java.name, classLoader))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `ignores anything it's seen before`() {
|
||||||
|
val filter = DuplicateRegistrationFilter(setOf("foo.bar", "foo.baz"))
|
||||||
|
|
||||||
|
assertTrue(filter.shouldNotify(ActuallyAContract::class.java.name, classLoader))
|
||||||
|
assertFalse(filter.shouldNotify(ActuallyAContract::class.java.name, classLoader))
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user