(Spring)外壳中的(Spring)状态:未生产单个

嘿,自动完成的交互式shell,帮助等等呢?而且没有麻烦,甚至在JVM上也没有?


邮差对我上班感到头疼。尽管用语言来说我们都是TDD,并且通过Cucumber的红灯我们看到了到底是什么破了,但是实际上我不得不更频繁地在Postman界面中发送REST请求。在工作开始时,有必要获取身份验证令牌(创建请求和验证请求,用户是不同的),然后从书签下载,编辑参数并启动其他请求。单击-单击-单击。以不同的顺序。我已经用cURL编写了脚本,并在IDEA中发出了请求-这不方便。切换到自动测试的理想动力,这些只是要求了解在服务状态,其版本,其背后的大型机,房屋的天气等特定时刻组合中发生的情况,并且当然不属于回归测试范围。连连单击开始吃太多时间,增加了鼠标的续航力。


Spring Shell, shell , Spring. , . , — . — shell, . , — Spring State Machine. , — , — , , Kotlin, Akka "" . State Machine , .



Spring Initializr Gradle Kotlin. .


curl 'https://start.spring.io/starter.zip?type=gradle-project&language=kotlin&bootVersion=2.2.6.RELEASE&baseDir=shell-state&groupId=me.votez.spring&artifactId=shell-state&name=shell-state&description=Demo%20project%20for%20Spring%20State%20Machine%20and%20Shell&packageName=me.votez.spring.shellstate&packaging=jar&javaVersion=1.8' --compressed --output shellstate.zip && unzip shellstate.zip

Spring Shell gradle


    implementation("org.springframework.shell:spring-shell-starter:2.0.0.RELEASE")


(shell). , ShellComponent ( ) , ShellMethod , . , ShellOption. , Bean Validation. , Enum ( , help).


— . — , , actuator .…
( runBlocking — )


package me.votez.spring.shellstate

import org.springframework.shell.standard.ShellComponent
import org.springframework.shell.standard.ShellMethod
import org.springframework.shell.standard.ShellOption
import kotlinx.coroutines.*
import org.springframework.shell.standard.ShellMethodAvailability
import java.util.*
import kotlin.random.Random

@ShellComponent
class ServerCommands {
    private var token: String? = null

    @ShellMethod("Authenticate and obtain token")
    fun login(
           @ShellOption name:String, 
           @ShellOption password:String, 
           @ShellOption(defaultValue = "admin") scope: String) = runBlocking {
            token = UUID.randomUUID().toString()
            delay(2_000)
            "Connected"
        }
    }

    @ShellMethod("List projects regstered on server")
    fun list(
        @ShellOption(defaultValue = "PROJECT", help = "Possible values are PROJECT and USER") type:EntityType) = when(type) {
        EntityType.PROJECT -> listOf("Roga i Kopita", "Svetliy Put", "NIICHAVO")
        EntityType.USER -> listOf( "Ivanov", "Petrov", "Sidorov")
    }
}

enum class EntityType {
    PROJECT,
    USER
}

. IntelliJ IDEA, Spring Shell JLine, Linux, MacOS Windows, IDE — .


$ bash ./gradlew build
$ java -jar build/libs/shell-state-0.0.1-SNAPSHOT.jar 

help, . clear, exit, quit, script, stacktrace.


2020-05-03 12:49:35.442  INFO 23211 --- [           main] m.v.s.s.ShellStateApplicationKt          : Started ShellStateApplicationKt in 1.036 seconds (JVM running for 0.936)
shell:>help
AVAILABLE COMMANDS

Built-In Commands
        clear: Clear the shell screen.
        exit, quit: Exit the shell.
        help: Display help about available commands.
        script: Read and execute commands from a file.
        stacktrace: Display the full stacktrace of the last error.

Server Commands
        list: List projects registered on server
        login: Authenticate and obtain token

shell:>help list

NAME
        list - List projects registered on server

SYNOPSYS
        list [[--type] entity-type]  

OPTIONS
        --type  entity-type
                Possible values are PROJECT and USER
                [Optional, default = PROJECT]

. login list L, . l TAB , o TAB, login. . , > login root 123456 , — Connected. list .



list , list . :



    @ShellMethodAvailability("list")
    fun listAvailable() = if (token != null) Availability.available()  else Availability.unavailable("cannot run without auth token")

shell, , . help , .


2020-05-02 13:30:12.593  INFO 4443 --- [           main] m.v.s.s.ShellStateApplicationKt          : Started ShellStateApplicationKt in 1.525 seconds (JVM running for 1.252)
shell:>list
Command 'list' exists but is not currently available because cannot run without auth token
Details of the error have been omitted. You can use the stacktrace command to print the full stacktrace.
shell:>help
AVAILABLE COMMANDS

Built-In Commands
        clear: Clear the shell screen.
        exit, quit: Exit the shell.
        help: Display help about available commands.
        script: Read and execute commands from a file.
        stacktrace: Display the full stacktrace of the last error.

Server Commands
      * list: List projects regstered on server
        login: Authenticate and obtain token

Commands marked with (*) are currently unavailable.
Type `help <command>` to learn more.

shell:>help list

NAME
        list - List projects registered on server

SYNOPSYS
        list [[--type] entity-type]  

OPTIONS
        --type  entity-type
                Possible values are PROJECT and USER
                [Optional, default = PROJECT]

CURRENTLY UNAVAILABLE
        This command is currently not available because cannot run without auth token.


, . , , , . command prompt, . , application.properties — , Spring Framework ( ). prompt , .


PrompProvider, , JLine.


@ConfigurationProperties(prefix="shell")
class ServerCommands : PromptProvider

    lateinit var env: String //   application.properties

    override fun getPrompt(): AttributedString =
            AttributedString("${env}:>",
                    AttributedStyle.DEFAULT.foreground(
                            if (token == null) AttributedStyle.YELLOW else AttributedStyle.GREEN))

, . .


, , (soap, protobuf ) — , - . , .


Spring State Machine


, . . , , , . , … , .


Spring State Machine.


, (), -. — The Evolution of Trust. , () . xml — , - .


, . , "" . Spring State Machine , , .


, . , . — Spring SM , . " ", - , - , , — .


, , . - — , .


?


, .

, "" . . ( ) , Thread Pool, shell, SSM - — .


command prompt " ", .


, . Quick Start.


, — . — command prompt. , , — , token. null-safe lateinit.
.


override fun configure(transitions: StateMachineTransitionConfigurer<State, Event>) {
        transitions
                .withExternal()
                .source(State.INIT).target(State.CONNECTING)
                .event(Event.LOGIN)
                .and()
                .withExternal()
                .source(State.CONNECTING).target(State.READY).event(Event.CONNECTED)
                .action { context -> context.extendedState.variables["token"] = context.messageHeaders["token"] }.and()
                .withExternal()
                .source(State.CONNECTING).target(State.INIT).event(Event.FAILED).and()
                .withInternal()
                .source(State.READY).event(Event.COMMAND).and()
                .withExternal()
                .source(State.READY).target(State.CONNECTING).event(Event.LOGIN)
    }

....
enum class State {    INIT, CONNECTING, READY }
enum class Event {  LOGIN, CONNECTED, FAILED, COMMAND }

— , — . Spring. , , . .


. login:


    @Autowired
    lateinit var stateMachine: StateMachine<State, Event>

   //    null
    lateinit var token: String

    @ShellMethod("Authenticate and obtain token")
    fun login(
            @ShellOption name: String,
            @ShellOption password: String,
            @ShellOption(defaultValue = "admin") scope: String) =
            runBlocking {
                stateMachine.sendEvent(
                        MessageBuilder.createMessage(Event.LOGIN, MessageHeaders(mapOf("login" to name))))
                delay(1_000)
                token = UUID.randomUUID().toString()
                stateMachine.sendEvent(
                        MessageBuilder.createMessage(Event.CONNECTED, MessageHeaders(mapOf("token" to token))))
                "Connected"
            }
...

command prompt:


    private val colors = mapOf(State.READY to AttributedStyle.DEFAULT.foreground(AttributedStyle.GREEN))
            .withDefault { AttributedStyle.DEFAULT.foreground(AttributedStyle.YELLOW) }

    override fun getPrompt(): AttributedString =
            AttributedString("${env}:>", colors.getValue(stateMachine.state.id))

:


    @ShellMethodAvailability("list")
    fun listAvailable() =
            if (stateMachine.state.id == State.READY) Availability.available()
            else Availability.unavailable("requires authentication performed first")

Spring State Machine — (guards), , , , , .



当需要对非平凡任务进行部分自动化时,Spring Shell是针对特定实用程序进行项目开发的出色解决方案


尽管存在偏见,Spring State Machine是许多社区项目中的另一个项目,值得更多关注,它是一项相关技术。


示例代码可在GitHub上获得



All Articles