Skip to content

Commit

Permalink
Remove the need to explicitly include custom workflows and actions.
Browse files Browse the repository at this point in the history
Change-Id: I914b3f16bba8ad261214164c57c9644299856f98
Closes-Bug: #1770567
  • Loading branch information
danieljasinski committed May 21, 2018
1 parent 993487b commit aa876a6
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 96 deletions.
Expand Up @@ -135,6 +135,9 @@ val Method.objectReferenceAttributeClass: Class<*>? get() =
val Method.isPublic get() =
Modifier.isPublic(modifiers)

val Method.isStatic get() =
Modifier.isStatic(modifiers)

val <T> Class<T>.isAbstract: Boolean get() =
Modifier.isAbstract(modifiers)

Expand Down Expand Up @@ -176,7 +179,7 @@ private fun <T> Class<T>.subclassesIn(packageName: String): List<Class<*>> =
.filter { it.isSubclassOf(this) }
.toList()

private fun classesIn(packageName: String): Sequence<Class<*>> =
fun classesIn(packageName: String): Sequence<Class<*>> =
ClassPath.from(loader).getTopLevelClassesRecursive(packageName).asSequence()
.map { classForName(it.name) }
.filterNotNull()
Expand Down
Expand Up @@ -6,7 +6,7 @@ package net.juniper.contrail.vro.tests.actions

import net.juniper.contrail.vro.tests.ScriptTestEngine
import spock.lang.Specification
import static net.juniper.contrail.vro.workflows.custom.CustomActionsKt.loadCustomActions
import static net.juniper.contrail.vro.workflows.custom.Custom.loadCustomActions
import static net.juniper.contrail.vro.tests.JsTesterKt.utilsName

abstract class ActionSpec extends Specification {
Expand Down
Expand Up @@ -22,7 +22,7 @@ import java.nio.file.Paths
import static net.juniper.contrail.vro.config.ProjectInfoKt.globalProjectInfo
import static net.juniper.contrail.vro.schema.SchemaKt.buildSchema
import static net.juniper.contrail.vro.tests.JsTesterKt.utilsName
import static net.juniper.contrail.vro.workflows.custom.CustomWorkflowsKt.loadCustomWorkflows
import static net.juniper.contrail.vro.workflows.custom.Custom.loadCustomWorkflows

abstract class WorkflowSpec extends Specification {
Dependencies dependencies
Expand Down
@@ -0,0 +1,17 @@
/*
* Copyright (c) 2018 Juniper Networks, Inc. All rights reserved.
*/

@file:JvmName("Custom")

package net.juniper.contrail.vro.workflows.custom

import net.juniper.contrail.vro.workflows.dsl.WorkflowDefinition
import net.juniper.contrail.vro.schema.Schema
import net.juniper.contrail.vro.workflows.model.Action

fun loadCustomWorkflows(schema: Schema): List<WorkflowDefinition> =
WorkflowLoader.load(schema).toList()

fun loadCustomActions(version: String, packageName: String): List<Action> =
ActionLoader.load().map { it(version, packageName) }.toList()

This file was deleted.

This file was deleted.

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2018 Juniper Networks, Inc. All rights reserved.
*/

package net.juniper.contrail.vro.workflows.custom

import net.juniper.contrail.vro.config.classesIn
import net.juniper.contrail.vro.config.isStatic
import net.juniper.contrail.vro.schema.Schema
import net.juniper.contrail.vro.workflows.dsl.WorkflowDefinition
import java.lang.reflect.Method

private val workflowScriptsDirectory = "workflows"
private val actionScriptsDirectory = "actions"

object ScriptLoader {
private fun load(path: String): String =
ScriptLoader::class.java
.getResourceAsStream(path)
.bufferedReader()
.use { it.readText() }

fun loadActionScript(name: String): String =
load("/$actionScriptsDirectory/$name.js")

fun loadWorkflowScript(name: String): String =
load("/$workflowScriptsDirectory/$name.js")
}

object WorkflowLoader {
fun load(schema: Schema): Sequence<WorkflowDefinition> =
classesIn(WorkflowLoader::class.java.`package`.name)
.filter { it.hasWorkflowDefinitions }
.flatMap { it.workflowDefinitions(schema) }
}

object ActionLoader {
fun load(): Sequence<ActionDefinition> =
classesIn(ActionLoader::class.java.`package`.name)
.filter { it.hasActionDefinitions }
.flatMap { it.actionDefinitions() }
}

private val Class<*>.hasWorkflowDefinitions get() =
declaredMethods.any { it.definesWorkflow }

private val Class<*>.hasActionDefinitions get() =
declaredMethods.any { it.definesAction }

private fun Class<*>.workflowDefinitions(schema: Schema) =
declaredMethods.asSequence()
.filter { it.definesWorkflow }
.map { it.createWorkflowDefinition(schema) }

private fun Class<*>.actionDefinitions() =
declaredMethods.asSequence()
.filter { it.definesAction }
.map { it.createActionDefinition() }

private fun Method.createWorkflowDefinition(schema: Schema): WorkflowDefinition = when {
takesNoParameters -> invoke(declaringClass)
takesOnlySchema -> invoke(declaringClass, schema)
else -> throw IllegalArgumentException("Cannot create workflow definition using method '$this' of class '$declaringClass'.")
} as WorkflowDefinition

private fun Method.createActionDefinition(): ActionDefinition = when {
takesNoParameters -> invoke(declaringClass)
else -> throw IllegalArgumentException("Cannot create action definition using method '$this' of class '$declaringClass'.")
} as ActionDefinition

private val Method.definesWorkflow get() =
isStatic && returnType == WorkflowDefinition::class.java && takesWorkflowDefinitionParameters

private val Method.takesWorkflowDefinitionParameters get() =
takesNoParameters || takesOnlySchema

private val Method.takesNoParameters get() =
parameterCount == 0

private val Method.takesOnlySchema get() =
parameterCount == 1 && parameters[0].type == Schema::class.java

private val Method.definesAction get() =
isStatic && returnType == ActionDefinition::class.java && takesNoParameters

Expand Up @@ -11,23 +11,6 @@ import net.juniper.contrail.vro.workflows.dsl.inCategory
import net.juniper.contrail.vro.workflows.dsl.withScript
import net.juniper.contrail.vro.workflows.dsl.workflow

val workflowScriptsDirectory = "workflows"
val actionScriptsDirectory = "actions"

object ScriptLoader {
private fun load(path: String): String =
ScriptLoader::class.java
.getResourceAsStream(path)
.bufferedReader()
.use { it.readText() }

fun loadActionScript(name: String): String =
load("/$actionScriptsDirectory/$name.js")

fun loadWorkflowScript(name: String): String =
load("/$workflowScriptsDirectory/$name.js")
}

fun WorkflowDefinition.withScriptFile(name: String, setup: ParameterDefinition) =
withScript(ScriptLoader.loadWorkflowScript(name), setup)

Expand Down

0 comments on commit aa876a6

Please sign in to comment.