Remove CordApps JARs from node classpath [CORDA-1135] (#2691)

This commit is contained in:
igor nitto 2018-03-14 16:42:23 +00:00 committed by GitHub
parent a24a2105b1
commit 2cff495553
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 36 additions and 20 deletions

View File

@ -52,13 +52,19 @@ data class LedgerTransaction @JvmOverloads constructor(
private companion object {
@JvmStatic
private fun createContractFor(className: ContractClassName): Try<Contract> {
return Try.on { this::class.java.classLoader.loadClass(className).asSubclass(Contract::class.java).getConstructor().newInstance() }
private fun createContractFor(className: ContractClassName, classLoader: ClassLoader?): Try<Contract> {
return Try.on {
(classLoader ?: this::class.java.classLoader)
.loadClass(className)
.asSubclass(Contract::class.java)
.getConstructor()
.newInstance()
}
}
}
private val contracts: Map<ContractClassName, Try<Contract>> = (inputs.map { it.state.contract } + outputs.map { it.contract })
.toSet().map { it to createContractFor(it) }.toMap()
private val contracts: Map<ContractClassName, Try<Contract>> = (inputs.map { it.state } + outputs)
.map { it.contract to createContractFor(it.contract, it.data::class.java.classLoader) }.toMap()
val inputStates: List<ContractState> get() = inputs.map { it.state.data }

View File

@ -34,7 +34,7 @@ abstract class AbstractCashSelection {
fun getInstance(metadata: () -> java.sql.DatabaseMetaData): AbstractCashSelection {
return instance.get() ?: {
val _metadata = metadata()
val cashSelectionAlgos = ServiceLoader.load(AbstractCashSelection::class.java).toList()
val cashSelectionAlgos = ServiceLoader.load(AbstractCashSelection::class.java, this::class.java.classLoader).toList()
val cashSelectionAlgo = cashSelectionAlgos.firstOrNull { it.isCompatible(_metadata) }
cashSelectionAlgo?.let {
instance.set(cashSelectionAlgo)

View File

@ -52,7 +52,8 @@ class CordaPersistence(
val dataSource: DataSource,
databaseConfig: DatabaseConfig,
schemas: Set<MappedSchema>,
attributeConverters: Collection<AttributeConverter<*, *>> = emptySet()
attributeConverters: Collection<AttributeConverter<*, *>> = emptySet(),
val cordappClassLoader: ClassLoader? = null
) : Closeable {
companion object {
private val log = contextLogger()
@ -61,7 +62,7 @@ class CordaPersistence(
private val defaultIsolationLevel = databaseConfig.transactionIsolationLevel
val hibernateConfig: HibernateConfiguration by lazy {
transaction {
HibernateConfiguration(schemas, databaseConfig, attributeConverters)
HibernateConfiguration(schemas, databaseConfig, attributeConverters, cordappClassLoader)
}
}
val entityManagerFactory get() = hibernateConfig.sessionFactoryForRegisteredSchemas

View File

@ -9,6 +9,8 @@ import org.hibernate.boot.MetadataSources
import org.hibernate.boot.model.naming.Identifier
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder
import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService
import org.hibernate.cfg.Configuration
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment
@ -26,7 +28,8 @@ import javax.persistence.AttributeConverter
class HibernateConfiguration(
schemas: Set<MappedSchema>,
private val databaseConfig: DatabaseConfig,
private val attributeConverters: Collection<AttributeConverter<*, *>>
private val attributeConverters: Collection<AttributeConverter<*, *>>,
val cordappClassLoader: ClassLoader? = null
) {
companion object {
private val logger = contextLogger()
@ -60,7 +63,7 @@ class HibernateConfiguration(
schema.mappedTypes.forEach { config.addAnnotatedClass(it) }
}
val sessionFactory = buildSessionFactory(config, metadataSources, databaseConfig.serverNameTablePrefix)
val sessionFactory = buildSessionFactory(config, metadataSources, databaseConfig.serverNameTablePrefix, cordappClassLoader)
logger.info("Created session factory for schemas: $schemas")
// export Hibernate JMX statistics
@ -87,8 +90,15 @@ class HibernateConfiguration(
}
}
private fun buildSessionFactory(config: Configuration, metadataSources: MetadataSources, tablePrefix: String): SessionFactory {
private fun buildSessionFactory(config: Configuration, metadataSources: MetadataSources, tablePrefix: String, cordappClassLoader: ClassLoader?): SessionFactory {
config.standardServiceRegistryBuilder.applySettings(config.properties)
if (cordappClassLoader != null) {
config.standardServiceRegistryBuilder.addService(
ClassLoaderService::class.java,
ClassLoaderServiceImpl(cordappClassLoader))
}
val metadata = metadataSources.getMetadataBuilder(config.standardServiceRegistryBuilder.build()).run {
applyPhysicalNamingStrategy(object : PhysicalNamingStrategyStandardImpl() {
override fun toPhysicalTableName(name: Identifier?, context: JdbcEnvironment?): Identifier {

View File

@ -18,7 +18,8 @@ private typealias MapCreationFunction = (Map<*, *>) -> Map<*, *>
* Serialization / deserialization of certain supported [Map] types.
*/
class MapSerializer(private val declaredType: ParameterizedType, factory: SerializerFactory) : AMQPSerializer<Any> {
override val type: Type = declaredType as? DeserializedParameterizedType ?: DeserializedParameterizedType.make(SerializerFactory.nameForType(declaredType))
override val type: Type = (declaredType as? DeserializedParameterizedType) ?:
DeserializedParameterizedType.make(SerializerFactory.nameForType(declaredType), factory.classloader)
override val typeDescriptor: Symbol = Symbol.valueOf(
"$DESCRIPTOR_DOMAIN:${factory.fingerPrinter.fingerprint(type)}")

View File

@ -81,8 +81,6 @@ public class CordaCaplet extends Capsule {
T cp = super.attribute(attr);
(new File(baseDir, "cordapps")).mkdir();
augmentClasspath((List<Path>) cp, new File(baseDir, "cordapps"));
augmentClasspath((List<Path>) cp, new File(baseDir, "plugins"));
// Add additional directories of JARs to the classpath (at the end). e.g. for JDBC drivers
try {
List<String> jarDirs = nodeConfig.getStringList("jarDirs");

View File

@ -639,7 +639,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
protected open fun initialiseDatabasePersistence(schemaService: SchemaService, identityService: IdentityService): CordaPersistence {
val props = configuration.dataSourceProperties
if (props.isEmpty()) throw DatabaseConfigurationException("There must be a database configured.")
val database = configureDatabase(props, configuration.database, identityService, schemaService)
val database = configureDatabase(props, configuration.database, identityService, schemaService, cordappLoader.appClassLoader)
// Now log the vendor string as this will also cause a connection to be tested eagerly.
logVendorString(database, log)
runOnStop += database::close
@ -874,7 +874,8 @@ internal class NetworkMapCacheEmptyException : Exception()
fun configureDatabase(hikariProperties: Properties,
databaseConfig: DatabaseConfig,
identityService: IdentityService,
schemaService: SchemaService = NodeSchemaService()): CordaPersistence {
schemaService: SchemaService = NodeSchemaService(),
cordappClassLoader: ClassLoader? = null): CordaPersistence {
// Register the AbstractPartyDescriptor so Hibernate doesn't warn when encountering AbstractParty. Unfortunately
// Hibernate warns about not being able to find a descriptor if we don't provide one, but won't use it by default
// so we end up providing both descriptor and converter. We should re-examine this in later versions to see if
@ -882,5 +883,5 @@ fun configureDatabase(hikariProperties: Properties,
JavaTypeDescriptorRegistry.INSTANCE.addDescriptor(AbstractPartyDescriptor(identityService))
val dataSource = DataSourceFactory.createDataSource(hikariProperties)
val attributeConverters = listOf(AbstractPartyToX500NameAsStringConverter(identityService))
return CordaPersistence(dataSource, databaseConfig, schemaService.schemaOptions.keys, attributeConverters)
return CordaPersistence(dataSource, databaseConfig, schemaService.schemaOptions.keys, attributeConverters, cordappClassLoader)
}

View File

@ -43,8 +43,7 @@ import kotlin.streams.toList
*/
class CordappLoader private constructor(private val cordappJarPaths: List<RestrictedURL>) {
val cordapps: List<Cordapp> by lazy { loadCordapps() + coreCordapp }
internal val appClassLoader: ClassLoader = URLClassLoader(cordappJarPaths.stream().map { it.url }.toTypedArray(), javaClass.classLoader)
val appClassLoader: ClassLoader = URLClassLoader(cordappJarPaths.stream().map { it.url }.toTypedArray(), javaClass.classLoader)
init {
if (cordappJarPaths.isEmpty()) {

View File

@ -160,7 +160,7 @@ object NodeInterestRates {
}
private fun addDefaultFixes() {
knownFixes = parseFile(IOUtils.toString(Thread.currentThread().contextClassLoader.getResourceAsStream("net/corda/irs/simulation/example.rates.txt"), Charsets.UTF_8.name()))
knownFixes = parseFile(IOUtils.toString(this::class.java.classLoader.getResourceAsStream("net/corda/irs/simulation/example.rates.txt"), Charsets.UTF_8.name()))
}
}

View File

@ -102,7 +102,7 @@ open class MockServices private constructor(
val cordappLoader = CordappLoader.createWithTestPackages(cordappPackages)
val dataSourceProps = makeTestDataSourceProperties()
val schemaService = NodeSchemaService(cordappLoader.cordappSchemas)
val database = configureDatabase(dataSourceProps, DatabaseConfig(), identityService, schemaService)
val database = configureDatabase(dataSourceProps, DatabaseConfig(), identityService, schemaService, cordappLoader.appClassLoader)
val mockService = database.transaction {
object : MockServices(cordappLoader, identityService, networkParameters, initialIdentity, moreKeys) {
override val vaultService: VaultService = makeVaultService(database.hibernateConfig, schemaService)