Make the IRS Demo web api an api plugin (scanned from the Node classpath) and use the same permission checking entry point for web api's as the scheduler.

Fix whitespace

Change ProtocolLogicRefFactory to use Map<String, Set<String>> as whitelist definition
This commit is contained in:
Matthew Nesbit
2016-07-06 13:23:41 +01:00
parent a1177f05c1
commit 1fb4371de9
15 changed files with 186 additions and 55 deletions

View File

@ -9,6 +9,7 @@ import com.r3corda.core.crypto.Party
import com.r3corda.core.messaging.MessagingService
import com.r3corda.core.messaging.runOnNextMessage
import com.r3corda.core.node.CityDatabase
import com.r3corda.core.node.CordaPluginRegistry
import com.r3corda.core.node.NodeInfo
import com.r3corda.core.node.PhysicalLocation
import com.r3corda.core.node.services.*
@ -97,7 +98,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
// Internal only
override val monitoringService: MonitoringService = MonitoringService(MetricRegistry())
override val protocolLogicRefFactory = ProtocolLogicRefFactory()
override val protocolLogicRefFactory: ProtocolLogicRefFactory get() = protocolLogicFactory
override fun <T> startProtocol(loggerName: String, logic: ProtocolLogic<T>): ListenableFuture<T> {
return smm.add(loggerName, logic)
@ -124,6 +125,7 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
lateinit var net: MessagingService
lateinit var api: APIServer
lateinit var scheduler: SchedulerService
lateinit var protocolLogicFactory: ProtocolLogicRefFactory
var isPreviousCheckpointsPresent = false
private set
@ -158,6 +160,8 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
checkpointStorage,
serverThread)
protocolLogicFactory = initialiseProtocolLogicFactory()
// This object doesn't need to be referenced from this class because it registers handlers on the network
// service and so that keeps it from being collected.
DataVendingService(net, storage, services.networkMapCache)
@ -180,6 +184,19 @@ abstract class AbstractNode(val dir: Path, val configuration: NodeConfiguration,
return this
}
private fun initialiseProtocolLogicFactory(): ProtocolLogicRefFactory {
val serviceLoader = ServiceLoader.load(CordaPluginRegistry::class.java)
val pluginRegistries = serviceLoader.toList()
val protocolWhitelist = HashMap<String, Set<String>>()
for (plugin in pluginRegistries) {
for (protocol in plugin.requiredProtocols) {
protocolWhitelist.merge(protocol.key, protocol.value, { x, y -> x + y })
}
}
return ProtocolLogicRefFactory(protocolWhitelist)
}
/**
* Run any tasks that are needed to ensure the node is in a correct state before running start()
*/

View File

@ -3,10 +3,11 @@ package com.r3corda.node.internal
import com.codahale.metrics.JmxReporter
import com.google.common.net.HostAndPort
import com.r3corda.core.messaging.MessagingService
import com.r3corda.core.node.CordaPluginRegistry
import com.r3corda.core.node.NodeInfo
import com.r3corda.core.node.ServiceHub
import com.r3corda.core.node.services.ServiceType
import com.r3corda.core.utilities.loggerFor
import com.r3corda.node.api.APIServer
import com.r3corda.node.serialization.NodeClock
import com.r3corda.node.services.config.NodeConfiguration
import com.r3corda.node.services.messaging.ArtemisMessagingService
@ -27,9 +28,9 @@ import java.io.RandomAccessFile
import java.lang.management.ManagementFactory
import java.net.InetSocketAddress
import java.nio.channels.FileLock
import java.nio.file.Files
import java.nio.file.Path
import java.time.Clock
import java.util.*
import javax.management.ObjectName
class ConfigurationException(message: String) : Exception(message)
@ -55,8 +56,7 @@ class ConfigurationException(message: String) : Exception(message)
*/
class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort, configuration: NodeConfiguration,
networkMapAddress: NodeInfo?, advertisedServices: Set<ServiceType>,
clock: Clock = NodeClock(),
val clientAPIs: List<Class<*>> = listOf()) : AbstractNode(dir, configuration, networkMapAddress, advertisedServices, clock) {
clock: Clock = NodeClock()) : AbstractNode(dir, configuration, networkMapAddress, advertisedServices, clock) {
companion object {
/** The port that is used by default if none is specified. As you know, 31337 is the most elite number. */
val DEFAULT_PORT = 31337
@ -109,12 +109,15 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
resourceConfig.register(ResponseFilter())
resourceConfig.register(api)
for(customAPIClass in clientAPIs) {
val customAPI = customAPIClass.getConstructor(APIServer::class.java).newInstance(api)
val serviceLoader = ServiceLoader.load(CordaPluginRegistry::class.java)
val pluginRegistries = serviceLoader.toList()
val webAPIsOnClasspath = pluginRegistries.flatMap { x -> x.webApis }
for (webapi in webAPIsOnClasspath) {
log.info("Add Plugin web API from attachment ${webapi.name}")
val customAPI = webapi.getConstructor(ServiceHub::class.java).newInstance(services)
resourceConfig.register(customAPI)
}
// Give the app a slightly better name in JMX rather than a randomly generated one and enable JMX
resourceConfig.addProperties(mapOf(ServerProperties.APPLICATION_NAME to "node.api",
ServerProperties.MONITORING_STATISTICS_MBEANS_ENABLED to "true"))
@ -187,5 +190,5 @@ class Node(dir: Path, val p2pAddr: HostAndPort, val webServerAddr: HostAndPort,
val ourProcessID: String = ManagementFactory.getRuntimeMXBean().name.split("@")[0]
f.setLength(0)
f.write(ourProcessID.toByteArray())
}
}
}

View File

@ -29,4 +29,11 @@ abstract class ServiceHubInternal : ServiceHub {
* itself, at which point this method would not be needed (by the scheduler)
*/
abstract fun <T> startProtocol(loggerName: String, logic: ProtocolLogic<T>): ListenableFuture<T>
override fun <T : Any> invokeProtocolAsync(logicType: Class<out ProtocolLogic<T>>, vararg args: Any?): ListenableFuture<T> {
val logicRef = protocolLogicRefFactory.create(logicType, *args)
@Suppress("UNCHECKED_CAST")
val logic = protocolLogicRefFactory.toProtocolLogic(logicRef) as ProtocolLogic<T>
return startProtocol(logicType.simpleName, logic)
}
}

View File

@ -9,6 +9,7 @@ import com.r3corda.core.crypto.signWithECDSA
import com.r3corda.core.math.CubicSplineInterpolator
import com.r3corda.core.math.Interpolator
import com.r3corda.core.math.InterpolatorFactory
import com.r3corda.core.node.CordaPluginRegistry
import com.r3corda.core.node.services.ServiceType
import com.r3corda.core.protocols.ProtocolLogic
import com.r3corda.core.utilities.ProgressTracker
@ -23,6 +24,7 @@ import java.io.InputStream
import java.math.BigDecimal
import java.security.KeyPair
import java.time.Clock
import java.time.Duration
import java.time.Instant
import java.time.LocalDate
import java.util.*
@ -93,6 +95,15 @@ object NodeInterestRates {
}
}
/**
* Register the protocol that is used with the Fixing integration tests
*/
class FixingServicePlugin : CordaPluginRegistry {
override val webApis: List<Class<*>> = emptyList()
override val requiredProtocols: Map<String, Set<String>> = mapOf(Pair(TwoPartyDealProtocol.FixingRoleDecider::class.java.name, setOf(Duration::class.java.name, StateRef::class.java.name)))
}
// File upload support
override val dataTypePrefix = "interest-rates"
override val acceptableFileExtensions = listOf(".rates", ".txt")

View File

@ -43,7 +43,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
// We have to allow Java boxed primitives but Kotlin warns we shouldn't be using them
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
val factory = ProtocolLogicRefFactory(setOf(TestProtocolLogic::class.java.name), setOf(NodeSchedulerServiceTest::class.java.name, Integer::class.java.name))
val factory = ProtocolLogicRefFactory(mapOf(Pair(TestProtocolLogic::class.java.name, setOf(NodeSchedulerServiceTest::class.java.name, Integer::class.java.name))))
val scheduler: NodeSchedulerService
val services: ServiceHub