initial import
This commit is contained in:
178
build.gradle
Normal file
178
build.gradle
Normal file
@@ -0,0 +1,178 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url 'http://repo.springsource.org/libs-release'}
|
||||
maven { url 'http://repo.springsource.org/plugins-release' }
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.springframework.build.gradle:propdeps-plugin:0.0.7")
|
||||
classpath('org.asciidoctor:asciidoctor-gradle-plugin:1.5.2')
|
||||
classpath("io.spring.gradle:docbook-reference-plugin:0.3.0")
|
||||
}
|
||||
}
|
||||
|
||||
configure(allprojects) {
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'idea'
|
||||
|
||||
sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
|
||||
group = 'org.springframework.statemachine'
|
||||
|
||||
[compileJava, compileTestJava]*.options*.compilerArgs = ['-Xlint:none']
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url "http://repo.springsource.org/libs-release" }
|
||||
}
|
||||
|
||||
task integrationTest(type: Test) {
|
||||
include '**/*IntegrationTests.*'
|
||||
}
|
||||
|
||||
test {
|
||||
exclude '**/*IntegrationTests.*'
|
||||
}
|
||||
|
||||
// servlet-api (2.5) and tomcat-servlet-api (3.0) classpath entries should not be
|
||||
// exported to dependent projects in Eclipse to avoid false compilation errors due
|
||||
// to changing APIs across these versions
|
||||
eclipse.classpath.file.whenMerged { classpath ->
|
||||
classpath.entries.findAll { entry -> entry.path.contains('servlet-api') }*.exported = false
|
||||
}
|
||||
}
|
||||
|
||||
configure(subprojects) { subproject ->
|
||||
apply from: "${rootProject.projectDir}/publish-maven.gradle"
|
||||
|
||||
jar {
|
||||
manifest.attributes['Implementation-Title'] = subproject.name
|
||||
manifest.attributes['Implementation-Version'] = subproject.version
|
||||
|
||||
from("${rootProject.projectDir}/src/dist") {
|
||||
include "license.txt"
|
||||
include "notice.txt"
|
||||
into "META-INF"
|
||||
expand(copyright: new Date().format('yyyy'), version: project.version)
|
||||
}
|
||||
}
|
||||
|
||||
javadoc {
|
||||
// /config/configuration/StateMachineConfiguration.html...
|
||||
// java.lang.ClassCastException: com.sun.tools.javadoc.MethodDocImpl cannot be cast
|
||||
// to com.sun.tools.javadoc.AnnotationTypeElementDocImpl
|
||||
// @Bean(name = StateMachineSystemConstants.DEFAULT_ID_STATEMACHINEFACTORY)
|
||||
// vs.
|
||||
// @Bean
|
||||
|
||||
enabled = false
|
||||
options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED
|
||||
options.author = true
|
||||
options.header = project.name
|
||||
verbose = true
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar, dependsOn:classes) {
|
||||
classifier = 'sources'
|
||||
from sourceSets.main.allJava
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar) {
|
||||
classifier = 'javadoc'
|
||||
from javadoc
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives sourcesJar
|
||||
archives javadocJar
|
||||
}
|
||||
}
|
||||
|
||||
project('spring-statemachine-core') {
|
||||
description = "Spring State Machine Core"
|
||||
|
||||
dependencies {
|
||||
compile "org.springframework:spring-messaging:$springVersion"
|
||||
|
||||
testCompile "org.springframework:spring-test:$springVersion"
|
||||
testCompile "org.hamcrest:hamcrest-core:$hamcrestVersion"
|
||||
testCompile "org.hamcrest:hamcrest-library:$hamcrestVersion"
|
||||
testCompile "junit:junit:$junitVersion"
|
||||
}
|
||||
}
|
||||
|
||||
configure(rootProject) {
|
||||
description = 'Spring State Machine'
|
||||
|
||||
apply plugin: 'org.asciidoctor.gradle.asciidoctor'
|
||||
apply plugin: "docbook-reference"
|
||||
|
||||
// don't publish the default jar for the root project
|
||||
configurations.archives.artifacts.clear()
|
||||
|
||||
reference {
|
||||
sourceDir = new File(asciidoctor.outputDir , 'docbook5')
|
||||
pdfFilename = "spring-statemachine-reference.pdf"
|
||||
epubFilename = "spring-statemachine-reference.epub"
|
||||
expandPlaceholders = ""
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
tasks.findAll { it.name.startsWith("reference") }.each{ it.dependsOn.add("asciidoctor") }
|
||||
}
|
||||
|
||||
asciidoctorj {
|
||||
version = '1.5.2'
|
||||
}
|
||||
|
||||
asciidoctor {
|
||||
sourceDir = file("docs/src/reference/asciidoc")
|
||||
backends = ['docbook5']
|
||||
options eruby: 'erubis'
|
||||
attributes docinfo: '',
|
||||
copycss : '',
|
||||
icons : 'font',
|
||||
'source-highlighter': 'prettify',
|
||||
sectanchors : '',
|
||||
toc2: '',
|
||||
idprefix: '',
|
||||
idseparator: '-',
|
||||
doctype: 'book',
|
||||
numbered: '',
|
||||
'spring-hadoop-version' : project.version,
|
||||
'spring-version' : springVersion,
|
||||
revnumber : project.version
|
||||
}
|
||||
|
||||
dependencies { // for integration tests
|
||||
}
|
||||
|
||||
task api(type: Javadoc) {
|
||||
group = 'Documentation'
|
||||
description = 'Generates aggregated Javadoc API documentation.'
|
||||
title = "${rootProject.description} ${version} API"
|
||||
options.memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED
|
||||
options.author = true
|
||||
options.header = rootProject.description
|
||||
options.overview = 'src/api/overview.html'
|
||||
options.links(
|
||||
'http://docs.jboss.org/jbossas/javadoc/4.0.5/connector'
|
||||
)
|
||||
source subprojects.collect { project ->
|
||||
project.sourceSets.main.allJava
|
||||
}
|
||||
destinationDir = new File(buildDir, "api")
|
||||
classpath = files(subprojects.collect { project ->
|
||||
project.sourceSets.main.compileClasspath
|
||||
})
|
||||
maxMemory = '1024m'
|
||||
}
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
description = 'Generates gradlew[.bat] scripts'
|
||||
gradleVersion = '2.2.1'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
14
docs/src/api/overview.html
Normal file
14
docs/src/api/overview.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<body>
|
||||
This document is the API specification for the Spring Statemachine project.
|
||||
<hr/>
|
||||
|
||||
<div id="overviewBody">
|
||||
<p>
|
||||
For further API reference and developer documentation, see the
|
||||
<a href="http://projects.spring.io/spring-statemachine/" target="_top">Spring Statemachine Project Page</a>.
|
||||
There you can find the latest news, links to documentation, books, presentations and webinars.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
599
docs/src/api/stylesheet.css
Normal file
599
docs/src/api/stylesheet.css
Normal file
@@ -0,0 +1,599 @@
|
||||
/* Javadoc style sheet */
|
||||
/*
|
||||
Overall document style
|
||||
*/
|
||||
|
||||
@import url('resources/fonts/dejavu.css');
|
||||
|
||||
body {
|
||||
background-color:#ffffff;
|
||||
color:#353833;
|
||||
font-family:'DejaVu Sans', Arial, Helvetica, sans-serif;
|
||||
font-size:14px;
|
||||
margin:0;
|
||||
}
|
||||
a:link, a:visited {
|
||||
text-decoration:none;
|
||||
color:#4A6782;
|
||||
}
|
||||
a:hover, a:focus {
|
||||
text-decoration:none;
|
||||
color:#bb7a2a;
|
||||
}
|
||||
a:active {
|
||||
text-decoration:none;
|
||||
color:#4A6782;
|
||||
}
|
||||
a[name] {
|
||||
color:#353833;
|
||||
}
|
||||
a[name]:hover {
|
||||
text-decoration:none;
|
||||
color:#353833;
|
||||
}
|
||||
pre {
|
||||
font-family:'DejaVu Sans Mono', monospace;
|
||||
font-size:14px;
|
||||
}
|
||||
h1 {
|
||||
font-size:20px;
|
||||
}
|
||||
h2 {
|
||||
font-size:18px;
|
||||
}
|
||||
h3 {
|
||||
font-size:16px;
|
||||
font-style:italic;
|
||||
}
|
||||
h4 {
|
||||
font-size:13px;
|
||||
}
|
||||
h5 {
|
||||
font-size:12px;
|
||||
}
|
||||
h6 {
|
||||
font-size:11px;
|
||||
}
|
||||
ul {
|
||||
list-style-type:disc;
|
||||
}
|
||||
code, tt {
|
||||
font-family:'DejaVu Sans Mono', monospace;
|
||||
font-size:14px;
|
||||
padding-top:4px;
|
||||
margin-top:8px;
|
||||
line-height:1.4em;
|
||||
}
|
||||
dt code {
|
||||
font-family:'DejaVu Sans Mono', monospace;
|
||||
font-size:14px;
|
||||
padding-top:4px;
|
||||
}
|
||||
table tr td dt code {
|
||||
font-family:'DejaVu Sans Mono', monospace;
|
||||
font-size:14px;
|
||||
vertical-align:top;
|
||||
padding-top:4px;
|
||||
}
|
||||
sup {
|
||||
font-size:8px;
|
||||
}
|
||||
/*
|
||||
Document title and Copyright styles
|
||||
*/
|
||||
.clear {
|
||||
clear:both;
|
||||
height:0px;
|
||||
overflow:hidden;
|
||||
}
|
||||
.aboutLanguage {
|
||||
float:right;
|
||||
padding:0px 21px;
|
||||
font-size:11px;
|
||||
z-index:200;
|
||||
margin-top:-9px;
|
||||
}
|
||||
.legalCopy {
|
||||
margin-left:.5em;
|
||||
}
|
||||
.bar a, .bar a:link, .bar a:visited, .bar a:active {
|
||||
color:#FFFFFF;
|
||||
text-decoration:none;
|
||||
}
|
||||
.bar a:hover, .bar a:focus {
|
||||
color:#bb7a2a;
|
||||
}
|
||||
.tab {
|
||||
background-color:#0066FF;
|
||||
color:#ffffff;
|
||||
padding:8px;
|
||||
width:5em;
|
||||
font-weight:bold;
|
||||
}
|
||||
/*
|
||||
Navigation bar styles
|
||||
*/
|
||||
.bar {
|
||||
background-color:#4D7A97;
|
||||
color:#FFFFFF;
|
||||
padding:.8em .5em .4em .8em;
|
||||
height:auto;/*height:1.8em;*/
|
||||
font-size:11px;
|
||||
margin:0;
|
||||
}
|
||||
.topNav {
|
||||
background-color:#4D7A97;
|
||||
color:#FFFFFF;
|
||||
float:left;
|
||||
padding:0;
|
||||
width:100%;
|
||||
clear:right;
|
||||
height:2.8em;
|
||||
padding-top:10px;
|
||||
overflow:hidden;
|
||||
font-size:12px;
|
||||
}
|
||||
.bottomNav {
|
||||
margin-top:10px;
|
||||
background-color:#4D7A97;
|
||||
color:#FFFFFF;
|
||||
float:left;
|
||||
padding:0;
|
||||
width:100%;
|
||||
clear:right;
|
||||
height:2.8em;
|
||||
padding-top:10px;
|
||||
overflow:hidden;
|
||||
font-size:12px;
|
||||
}
|
||||
.subNav {
|
||||
background-color:#dee3e9;
|
||||
float:left;
|
||||
width:100%;
|
||||
overflow:hidden;
|
||||
font-size:12px;
|
||||
}
|
||||
.subNav div {
|
||||
clear:left;
|
||||
float:left;
|
||||
padding:0 0 5px 6px;
|
||||
text-transform:uppercase;
|
||||
}
|
||||
ul.navList, ul.subNavList {
|
||||
float:left;
|
||||
margin:0 25px 0 0;
|
||||
padding:0;
|
||||
}
|
||||
ul.navList li{
|
||||
list-style:none;
|
||||
float:left;
|
||||
padding: 5px 6px;
|
||||
text-transform:uppercase;
|
||||
}
|
||||
ul.subNavList li{
|
||||
list-style:none;
|
||||
float:left;
|
||||
}
|
||||
.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited {
|
||||
color:#FFFFFF;
|
||||
text-decoration:none;
|
||||
text-transform:uppercase;
|
||||
}
|
||||
.topNav a:hover, .bottomNav a:hover {
|
||||
text-decoration:none;
|
||||
color:#bb7a2a;
|
||||
text-transform:uppercase;
|
||||
}
|
||||
.navBarCell1Rev {
|
||||
background-color:#F8981D;
|
||||
color:#253441;
|
||||
margin: auto 5px;
|
||||
}
|
||||
.skipNav {
|
||||
position:absolute;
|
||||
top:auto;
|
||||
left:-9999px;
|
||||
overflow:hidden;
|
||||
}
|
||||
/*
|
||||
Page header and footer styles
|
||||
*/
|
||||
.header, .footer {
|
||||
clear:both;
|
||||
margin:0 20px;
|
||||
padding:5px 0 0 0;
|
||||
}
|
||||
.indexHeader {
|
||||
margin:10px;
|
||||
position:relative;
|
||||
}
|
||||
.indexHeader span{
|
||||
margin-right:15px;
|
||||
}
|
||||
.indexHeader h1 {
|
||||
font-size:13px;
|
||||
}
|
||||
.title {
|
||||
color:#2c4557;
|
||||
margin:10px 0;
|
||||
}
|
||||
.subTitle {
|
||||
margin:5px 0 0 0;
|
||||
}
|
||||
.header ul {
|
||||
margin:0 0 15px 0;
|
||||
padding:0;
|
||||
}
|
||||
.footer ul {
|
||||
margin:20px 0 5px 0;
|
||||
}
|
||||
.header ul li, .footer ul li {
|
||||
list-style:none;
|
||||
font-size:13px;
|
||||
}
|
||||
/*
|
||||
Heading styles
|
||||
*/
|
||||
div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 {
|
||||
background-color:#dee3e9;
|
||||
border:1px solid #d0d9e0;
|
||||
margin:0 0 6px -8px;
|
||||
padding:7px 5px;
|
||||
}
|
||||
ul.blockList ul.blockList ul.blockList li.blockList h3 {
|
||||
background-color:#dee3e9;
|
||||
border:1px solid #d0d9e0;
|
||||
margin:0 0 6px -8px;
|
||||
padding:7px 5px;
|
||||
}
|
||||
ul.blockList ul.blockList li.blockList h3 {
|
||||
padding:0;
|
||||
margin:15px 0;
|
||||
}
|
||||
ul.blockList li.blockList h2 {
|
||||
padding:0px 0 20px 0;
|
||||
}
|
||||
/*
|
||||
Page layout container styles
|
||||
*/
|
||||
.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer {
|
||||
clear:both;
|
||||
padding:10px 20px;
|
||||
position:relative;
|
||||
}
|
||||
.indexContainer {
|
||||
margin:10px;
|
||||
position:relative;
|
||||
font-size:12px;
|
||||
}
|
||||
.indexContainer h2 {
|
||||
font-size:13px;
|
||||
padding:0 0 3px 0;
|
||||
}
|
||||
.indexContainer ul {
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
.indexContainer ul li {
|
||||
list-style:none;
|
||||
padding-top:2px;
|
||||
}
|
||||
.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt {
|
||||
font-size:12px;
|
||||
font-weight:bold;
|
||||
margin:10px 0 0 0;
|
||||
color:#4E4E4E;
|
||||
}
|
||||
.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd {
|
||||
margin:5px 0 10px 0px;
|
||||
font-size:14px;
|
||||
font-family:'DejaVu Sans Mono',monospace;
|
||||
}
|
||||
.serializedFormContainer dl.nameValue dt {
|
||||
margin-left:1px;
|
||||
font-size:1.1em;
|
||||
display:inline;
|
||||
font-weight:bold;
|
||||
}
|
||||
.serializedFormContainer dl.nameValue dd {
|
||||
margin:0 0 0 1px;
|
||||
font-size:1.1em;
|
||||
display:inline;
|
||||
}
|
||||
/*
|
||||
List styles
|
||||
*/
|
||||
ul.horizontal li {
|
||||
display:inline;
|
||||
font-size:0.9em;
|
||||
}
|
||||
ul.inheritance {
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
ul.inheritance li {
|
||||
display:inline;
|
||||
list-style:none;
|
||||
}
|
||||
ul.inheritance li ul.inheritance {
|
||||
margin-left:15px;
|
||||
padding-left:15px;
|
||||
padding-top:1px;
|
||||
}
|
||||
ul.blockList, ul.blockListLast {
|
||||
margin:10px 0 10px 0;
|
||||
padding:0;
|
||||
}
|
||||
ul.blockList li.blockList, ul.blockListLast li.blockList {
|
||||
list-style:none;
|
||||
margin-bottom:15px;
|
||||
line-height:1.4;
|
||||
}
|
||||
ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList {
|
||||
padding:0px 20px 5px 10px;
|
||||
border:1px solid #ededed;
|
||||
background-color:#f8f8f8;
|
||||
}
|
||||
ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList {
|
||||
padding:0 0 5px 8px;
|
||||
background-color:#ffffff;
|
||||
border:none;
|
||||
}
|
||||
ul.blockList ul.blockList ul.blockList ul.blockList li.blockList {
|
||||
margin-left:0;
|
||||
padding-left:0;
|
||||
padding-bottom:15px;
|
||||
border:none;
|
||||
}
|
||||
ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast {
|
||||
list-style:none;
|
||||
border-bottom:none;
|
||||
padding-bottom:0;
|
||||
}
|
||||
table tr td dl, table tr td dl dt, table tr td dl dd {
|
||||
margin-top:0;
|
||||
margin-bottom:1px;
|
||||
}
|
||||
/*
|
||||
Table styles
|
||||
*/
|
||||
.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary {
|
||||
width:100%;
|
||||
border-left:1px solid #EEE;
|
||||
border-right:1px solid #EEE;
|
||||
border-bottom:1px solid #EEE;
|
||||
}
|
||||
.overviewSummary, .memberSummary {
|
||||
padding:0px;
|
||||
}
|
||||
.overviewSummary caption, .memberSummary caption, .typeSummary caption,
|
||||
.useSummary caption, .constantsSummary caption, .deprecatedSummary caption {
|
||||
position:relative;
|
||||
text-align:left;
|
||||
background-repeat:no-repeat;
|
||||
color:#253441;
|
||||
font-weight:bold;
|
||||
clear:none;
|
||||
overflow:hidden;
|
||||
padding:0px;
|
||||
padding-top:10px;
|
||||
padding-left:1px;
|
||||
margin:0px;
|
||||
white-space:pre;
|
||||
}
|
||||
.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link,
|
||||
.useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link,
|
||||
.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover,
|
||||
.useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover,
|
||||
.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active,
|
||||
.useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active,
|
||||
.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited,
|
||||
.useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited {
|
||||
color:#FFFFFF;
|
||||
}
|
||||
.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span,
|
||||
.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span {
|
||||
white-space:nowrap;
|
||||
padding-top:5px;
|
||||
padding-left:12px;
|
||||
padding-right:12px;
|
||||
padding-bottom:7px;
|
||||
display:inline-block;
|
||||
float:left;
|
||||
background-color:#F8981D;
|
||||
border: none;
|
||||
height:16px;
|
||||
}
|
||||
.memberSummary caption span.activeTableTab span {
|
||||
white-space:nowrap;
|
||||
padding-top:5px;
|
||||
padding-left:12px;
|
||||
padding-right:12px;
|
||||
margin-right:3px;
|
||||
display:inline-block;
|
||||
float:left;
|
||||
background-color:#F8981D;
|
||||
height:16px;
|
||||
}
|
||||
.memberSummary caption span.tableTab span {
|
||||
white-space:nowrap;
|
||||
padding-top:5px;
|
||||
padding-left:12px;
|
||||
padding-right:12px;
|
||||
margin-right:3px;
|
||||
display:inline-block;
|
||||
float:left;
|
||||
background-color:#4D7A97;
|
||||
height:16px;
|
||||
}
|
||||
.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab {
|
||||
padding-top:0px;
|
||||
padding-left:0px;
|
||||
padding-right:0px;
|
||||
background-image:none;
|
||||
float:none;
|
||||
display:inline;
|
||||
}
|
||||
.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd,
|
||||
.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd {
|
||||
display:none;
|
||||
width:5px;
|
||||
position:relative;
|
||||
float:left;
|
||||
background-color:#F8981D;
|
||||
}
|
||||
.memberSummary .activeTableTab .tabEnd {
|
||||
display:none;
|
||||
width:5px;
|
||||
margin-right:3px;
|
||||
position:relative;
|
||||
float:left;
|
||||
background-color:#F8981D;
|
||||
}
|
||||
.memberSummary .tableTab .tabEnd {
|
||||
display:none;
|
||||
width:5px;
|
||||
margin-right:3px;
|
||||
position:relative;
|
||||
background-color:#4D7A97;
|
||||
float:left;
|
||||
|
||||
}
|
||||
.overviewSummary td, .memberSummary td, .typeSummary td,
|
||||
.useSummary td, .constantsSummary td, .deprecatedSummary td {
|
||||
text-align:left;
|
||||
padding:0px 0px 12px 10px;
|
||||
width:100%;
|
||||
}
|
||||
th.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th,
|
||||
td.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td{
|
||||
vertical-align:top;
|
||||
padding-right:0px;
|
||||
padding-top:8px;
|
||||
padding-bottom:3px;
|
||||
}
|
||||
th.colFirst, th.colLast, th.colOne, .constantsSummary th {
|
||||
background:#dee3e9;
|
||||
text-align:left;
|
||||
padding:8px 3px 3px 7px;
|
||||
}
|
||||
td.colFirst, th.colFirst {
|
||||
white-space:nowrap;
|
||||
font-size:13px;
|
||||
}
|
||||
td.colLast, th.colLast {
|
||||
font-size:13px;
|
||||
}
|
||||
td.colOne, th.colOne {
|
||||
font-size:13px;
|
||||
}
|
||||
.overviewSummary td.colFirst, .overviewSummary th.colFirst,
|
||||
.overviewSummary td.colOne, .overviewSummary th.colOne,
|
||||
.memberSummary td.colFirst, .memberSummary th.colFirst,
|
||||
.memberSummary td.colOne, .memberSummary th.colOne,
|
||||
.typeSummary td.colFirst{
|
||||
width:25%;
|
||||
vertical-align:top;
|
||||
}
|
||||
td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover {
|
||||
font-weight:bold;
|
||||
}
|
||||
.tableSubHeadingColor {
|
||||
background-color:#EEEEFF;
|
||||
}
|
||||
.altColor {
|
||||
background-color:#FFFFFF;
|
||||
}
|
||||
.rowColor {
|
||||
background-color:#EEEEEF;
|
||||
}
|
||||
/*
|
||||
Content styles
|
||||
*/
|
||||
.description pre {
|
||||
margin-top:0;
|
||||
}
|
||||
.deprecatedContent {
|
||||
margin:0;
|
||||
padding:10px 0;
|
||||
}
|
||||
.docSummary {
|
||||
padding:0;
|
||||
}
|
||||
|
||||
ul.blockList ul.blockList ul.blockList li.blockList h3 {
|
||||
font-style:normal;
|
||||
}
|
||||
|
||||
div.block {
|
||||
font-size:14px;
|
||||
font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
|
||||
}
|
||||
|
||||
td.colLast div {
|
||||
padding-top:0px;
|
||||
}
|
||||
|
||||
|
||||
td.colLast a {
|
||||
padding-bottom:3px;
|
||||
}
|
||||
/*
|
||||
Formatting effect styles
|
||||
*/
|
||||
.sourceLineNo {
|
||||
color:green;
|
||||
padding:0 30px 0 0;
|
||||
}
|
||||
h1.hidden {
|
||||
visibility:hidden;
|
||||
overflow:hidden;
|
||||
font-size:10px;
|
||||
}
|
||||
.block {
|
||||
display:block;
|
||||
margin:3px 10px 2px 0px;
|
||||
color:#474747;
|
||||
}
|
||||
.deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink,
|
||||
.overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel,
|
||||
.seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink {
|
||||
font-weight:bold;
|
||||
}
|
||||
.deprecationComment, .emphasizedPhrase, .interfaceName {
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase,
|
||||
div.block div.block span.interfaceName {
|
||||
font-style:normal;
|
||||
}
|
||||
|
||||
div.contentContainer ul.blockList li.blockList h2{
|
||||
padding-bottom:0px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Spring
|
||||
*/
|
||||
|
||||
pre.code {
|
||||
background-color: #F8F8F8;
|
||||
border: 1px solid #CCCCCC;
|
||||
border-radius: 3px 3px 3px 3px;
|
||||
overflow: auto;
|
||||
padding: 10px;
|
||||
margin: 4px 20px 2px 0px;
|
||||
}
|
||||
|
||||
pre.code code, pre.code code * {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre.code code, pre.code code * {
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
4
docs/src/info/changelog.txt
Normal file
4
docs/src/info/changelog.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
SPRING STATEMACHINE CHANGELOG
|
||||
==================================
|
||||
http://projects.spring.io/spring-statemachine/
|
||||
|
||||
201
docs/src/info/license.txt
Normal file
201
docs/src/info/license.txt
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
21
docs/src/info/notice.txt
Normal file
21
docs/src/info/notice.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
======================================================================
|
||||
== NOTICE file corresponding to section 4 d of the Apache License, ==
|
||||
== Version 2.0, for the Spring Framework distribution. ==
|
||||
======================================================================
|
||||
|
||||
This product includes software developed by
|
||||
the Apache Software Foundation (http://www.apache.org).
|
||||
|
||||
The end-user documentation included with a redistribution, if any,
|
||||
must include the following acknowledgement:
|
||||
|
||||
"This product includes software developed by the Spring Framework
|
||||
Project (http://www.springframework.org)."
|
||||
|
||||
Alternately, this acknowledgement may appear in the software itself,
|
||||
if and wherever such third-party acknowledgements normally appear.
|
||||
|
||||
The names "Spring", "Spring Framework" and "Spring for Apache Hadoop"
|
||||
must not be used to endorse or promote products derived from this
|
||||
software without prior written permission. For written permission,
|
||||
please contact enquiries@springsource.com.
|
||||
24
docs/src/info/readme.txt
Normal file
24
docs/src/info/readme.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
SPRING STATEMACHINE
|
||||
------------------------
|
||||
http://projects.spring.io/spring-statemachine/
|
||||
|
||||
1. INTRODUCTION
|
||||
|
||||
Spring Statemachine is a framework extension introducing state machine
|
||||
concepts in a spring world.
|
||||
|
||||
2. RELEASE NOTES
|
||||
|
||||
This release comes with complete reference documentation. For further
|
||||
details, consult the provided javadoc for specific packages and classes.
|
||||
|
||||
3. DISTRIBUTION JAR FILES
|
||||
|
||||
The Spring Statemachine jars files can be found in the 'dist' directory.
|
||||
|
||||
4. GETTING STARTED
|
||||
|
||||
Please see the reference documentation.
|
||||
Additionally the blog at http://blog.spring.io as well
|
||||
as sections of interest in the reference documentation.
|
||||
|
||||
13
docs/src/reference/asciidoc/Guardfile
Normal file
13
docs/src/reference/asciidoc/Guardfile
Normal file
@@ -0,0 +1,13 @@
|
||||
require 'asciidoctor'
|
||||
require 'erb'
|
||||
|
||||
guard 'shell' do
|
||||
watch(/^.*\.adoc$/) {|m|
|
||||
Asciidoctor.render_file(m[0], :to_dir => "build/", :safe => Asciidoctor::SafeMode::UNSAFE, :attributes=> {'idprefix' => '', 'idseparator' => '-', 'copycss' => '', 'icons' => 'font', 'source-highlighter' => 'prettify', 'sectanchors' => '', 'doctype' => 'book','toc2' => '', 'spring-hadoop-version' => '2.1.0.BUILD-SNAPSHOT','spring-version' => '4.1.3.RELEASE', 'revnumber' => '2.1.0.BUILD-SNAPSHOT', 'numbered'=>'' })
|
||||
}
|
||||
end
|
||||
|
||||
guard 'livereload' do
|
||||
watch(%r{build/.+\.(css|js|html)$})
|
||||
end
|
||||
|
||||
16
docs/src/reference/asciidoc/appendix.adoc
Normal file
16
docs/src/reference/asciidoc/appendix.adoc
Normal file
@@ -0,0 +1,16 @@
|
||||
[[appendices]]
|
||||
= Appendices
|
||||
|
||||
:numbered!:
|
||||
|
||||
[appendix]
|
||||
== State Machine Concepts
|
||||
This appendix provides generic information about state machines.
|
||||
|
||||
=== Glossary
|
||||
|
||||
state machine::
|
||||
machine of sort.
|
||||
|
||||
state::
|
||||
a stage in a state machine.
|
||||
22
docs/src/reference/asciidoc/index-docinfo.xml
Normal file
22
docs/src/reference/asciidoc/index-docinfo.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<releaseinfo>{revnumber}</releaseinfo>
|
||||
<productname>Spring Statemachine</productname>
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Janne</firstname>
|
||||
<surname>Valkealahti</surname>
|
||||
<affiliation>Pivotal</affiliation>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<copyright>
|
||||
<year>2015</year>
|
||||
<holder>Pivotal Software, Inc.</holder>
|
||||
</copyright>
|
||||
|
||||
<legalnotice>
|
||||
<para>Copies of this document may be made for your own use and for
|
||||
distribution to others, provided that you do not charge any fee for such
|
||||
copies and further provided that each copy contains this Copyright
|
||||
Notice, whether distributed in print or electronically.</para>
|
||||
</legalnotice>
|
||||
|
||||
37
docs/src/reference/asciidoc/index.adoc
Normal file
37
docs/src/reference/asciidoc/index.adoc
Normal file
@@ -0,0 +1,37 @@
|
||||
:hadoop-Configuration: http://hadoop.apache.org/docs/r{hadoop-version}/api/org/apache/hadoop/conf/Configuration.html
|
||||
:hadoop-FileSystem: http://hadoop.apache.org/docs/r{hadoop-version}/api/org/apache/hadoop/fs/FileSystem.html
|
||||
:hadoop-Security: http://hadoop.apache.org/docs/r{hadoop-version}/hadoop-project-dist/hadoop-common/SecureMode.html
|
||||
:hadoop-Streaming: http://hadoop.apache.org/docs/r{hadoop-version}/hadoop-mapreduce-client/hadoop-mapreduce-client-core/HadoopStreaming.html
|
||||
:hadoop-DistributedCache: http://hadoop.apache.org/docs/r{hadoop-version}/hadoop-mapreduce-client/hadoop-mapreduce-client-core/DistributedCacheDeploy.html
|
||||
:hadoop-WordCount: http://hadoop.apache.org/docs/r{hadoop-version}/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapReduceTutorial.html#Example:_WordCount_v1.0
|
||||
:hadoop-FileSystemShell: http://hadoop.apache.org/docs/r{hadoop-version}/hadoop-project-dist/hadoop-common/FileSystemShell.html
|
||||
:hadoop-WebHdfs: http://hadoop.apache.org/docs/r{hadoop-version}/hadoop-project-dist/hadoop-hdfs/WebHDFS.html
|
||||
:hadoop-Hftp: http://hadoop.apache.org/docs/r{hadoop-version}/hadoop-project-dist/hadoop-hdfs/Hftp.html
|
||||
:java-ClassLoader: http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html
|
||||
:core-ApplicationContext: http://docs.spring.io/spring/docs/{spring-version}/javadoc-api/org/springframework/context/ApplicationContext.html
|
||||
:core-beans-factory-placeholderconfigurer: http://docs.spring.io/spring/docs/{spring-version}/spring-framework-reference/html/beans.html#beans-factory-placeholderconfigurer
|
||||
:core-beans-environment: http://docs.spring.io/spring/docs/{spring-version}/spring-framework-reference/html/beans.html#beans-environment
|
||||
:core-ResourcePatternResolver: http://docs.spring.io/spring/docs/{spring-version}/javadoc-api/org/springframework/core/io/support/ResourcePatternResolver.html
|
||||
:core-ref-util: http://docs.spring.io/spring/docs/{spring-version}/spring-framework-reference/html/xsd-config.html#xsd-config-body-schemas-util-properties
|
||||
:core-aop-schema-advisors: http://docs.spring.io/spring/docs/{spring-version}/spring-framework-reference/html/aop.html#aop-schema-advisors
|
||||
:core-dao: http://docs.spring.io/spring/docs/{spring-version}/spring-framework-reference/html/dao.html
|
||||
:core-dao-exceptions: http://docs.spring.io/spring/docs/{spring-version}/spring-framework-reference/html/dao.html#dao-exceptions
|
||||
:core-jdbc: http://docs.spring.io/spring/docs/{spring-version}/spring-framework-reference/html/jdbc.html
|
||||
:core-jdbc-JdbcTemplate: http://docs.spring.io/spring/docs/{spring-version}/spring-framework-reference/html/jdbc.html#jdbc-JdbcTemplate
|
||||
:shdp-FsShell: http://docs.spring.io/spring-hadoop/docs/{spring-hadoop-version}/api/org/springframework/data/hadoop/fs/FsShell.html
|
||||
:shdp-DistCp: http://docs.spring.io/spring-hadoop/docs/{spring-hadoop-version}/api/org/springframework/data/hadoop/fs/DistCp.html
|
||||
:shdp-HdfsResourceLoader: http://docs.spring.io/spring-hadoop/docs/{spring-hadoop-version}/api/org/springframework/data/hadoop/fs/HdfsResourceLoader.html
|
||||
:shdp-SpringDataStoreTextWriterConfigurerAdapter: http://docs.spring.io/spring-hadoop/docs/{spring-hadoop-version}/api/org/springframework/data/hadoop/store/config/annotation/SpringDataStoreTextWriterConfigurerAdapter.html
|
||||
:shdp-EnableDataStoreTextWriter: http://docs.spring.io/spring-hadoop/docs/{spring-hadoop-version}/api/org/springframework/data/hadoop/store/config/annotation/EnableDataStoreTextWriter.html
|
||||
:shdp-DataStoreTextWriterConfigurer: http://docs.spring.io/spring-hadoop/docs/{spring-hadoop-version}/api/org/springframework/data/hadoop/store/config/annotation/builders/DataStoreTextWriterConfigurer.html
|
||||
:shdp-DataStoreWriter: http://docs.spring.io/spring-hadoop/docs/{spring-hadoop-version}/api/org/springframework/data/hadoop/store/DataStoreWriter.html
|
||||
:spring-data-hadoop-boot-jar: spring-data-hadoop-boot-{spring-hadoop-version}.jar
|
||||
|
||||
= Spring Statemachine - Reference Documentation
|
||||
|
||||
include::preface.adoc[]
|
||||
include::introduction.adoc[]
|
||||
|
||||
[[springandhadoop]]
|
||||
include::sm.adoc[]
|
||||
include::appendix.adoc[]
|
||||
5
docs/src/reference/asciidoc/introduction.adoc
Normal file
5
docs/src/reference/asciidoc/introduction.adoc
Normal file
@@ -0,0 +1,5 @@
|
||||
[[introduction]]
|
||||
= Introduction
|
||||
|
||||
== Requirements
|
||||
TBD
|
||||
4
docs/src/reference/asciidoc/preface.adoc
Normal file
4
docs/src/reference/asciidoc/preface.adoc
Normal file
@@ -0,0 +1,4 @@
|
||||
[preface]
|
||||
== Preface
|
||||
Spring Statemachine is a framework for application developers to use
|
||||
state machine concepts with Spring.
|
||||
5
docs/src/reference/asciidoc/sm.adoc
Normal file
5
docs/src/reference/asciidoc/sm.adoc
Normal file
@@ -0,0 +1,5 @@
|
||||
[[statemachine]]
|
||||
= State Machine
|
||||
TBD
|
||||
|
||||
|
||||
4
gradle.properties
Normal file
4
gradle.properties
Normal file
@@ -0,0 +1,4 @@
|
||||
version=1.0.0.BUILD-SNAPSHOT
|
||||
springVersion = 4.1.4.RELEASE
|
||||
hamcrestVersion = 1.3
|
||||
junitVersion = 4.11
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Sat Jan 31 16:49:22 GMT 2015
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-bin.zip
|
||||
164
gradlew
vendored
Executable file
164
gradlew
vendored
Executable file
@@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >&-
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
||||
90
gradlew.bat
vendored
Normal file
90
gradlew.bat
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
60
publish-maven.gradle
Normal file
60
publish-maven.gradle
Normal file
@@ -0,0 +1,60 @@
|
||||
apply plugin: 'maven'
|
||||
|
||||
ext.optionalDeps = []
|
||||
ext.providedDeps = []
|
||||
|
||||
ext.optional = { optionalDeps << it }
|
||||
ext.provided = { providedDeps << it }
|
||||
|
||||
install {
|
||||
repositories.mavenInstaller {
|
||||
customizePom(pom, project)
|
||||
}
|
||||
}
|
||||
|
||||
def customizePom(pom, gradleProject) {
|
||||
pom.whenConfigured { generatedPom ->
|
||||
// respect 'optional' and 'provided' dependencies
|
||||
gradleProject.optionalDeps.each { dep ->
|
||||
generatedPom.dependencies.findAll { it.artifactId == dep.name }*.optional = true
|
||||
}
|
||||
gradleProject.providedDeps.each { dep ->
|
||||
generatedPom.dependencies.findAll { it.artifactId == dep.name }*.scope = 'provided'
|
||||
}
|
||||
|
||||
// eliminate test-scoped dependencies (no need in maven central poms)
|
||||
generatedPom.dependencies.removeAll { dep ->
|
||||
dep.scope == 'test'
|
||||
}
|
||||
|
||||
// add all items necessary for maven central publication
|
||||
generatedPom.project {
|
||||
name = gradleProject.description
|
||||
description = gradleProject.description
|
||||
url = 'https://github.com/spring-projects/spring-statemachine'
|
||||
organization {
|
||||
name = 'SpringSource'
|
||||
url = 'http://spring.io/spring-statemachine'
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name 'The Apache Software License, Version 2.0'
|
||||
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
||||
distribution 'repo'
|
||||
}
|
||||
}
|
||||
scm {
|
||||
url = 'https://github.com/spring-projects/spring-statemachine'
|
||||
connection = 'scm:git:git://github.com/spring-projects/spring-statemachine'
|
||||
developerConnection = 'scm:git:git://github.com/spring-projects/spring-statemachine'
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = 'jvalkeal'
|
||||
name = 'Janne Valkealahti'
|
||||
email = 'janne.valkealahti@gmail.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
settings.gradle
Normal file
3
settings.gradle
Normal file
@@ -0,0 +1,3 @@
|
||||
rootProject.name = 'spring-statemachine'
|
||||
|
||||
include 'spring-statemachine-core'
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.support.AbstractStateMachine;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
/**
|
||||
* Specialisation of a {@link StateMachine} using enums
|
||||
* as its {@link State} and event types.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class EnumStateMachine<S extends Enum<S>, E extends Enum<E>> extends AbstractStateMachine<S, E> {
|
||||
|
||||
/**
|
||||
* Instantiates a new enum state machine.
|
||||
*
|
||||
* @param states the states
|
||||
* @param transitions the transitions
|
||||
* @param initialState the initial state
|
||||
*/
|
||||
public EnumStateMachine(Collection<State<S, E>> states, Collection<Transition<S, E>> transitions,
|
||||
State<S, E> initialState) {
|
||||
super(states, transitions, initialState);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Extended states are used to supplement state machine with a variables. If
|
||||
* extended state is used a complete condition of a state machine is a
|
||||
* combination of its state an extended state variables.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public interface ExtendedState {
|
||||
|
||||
/**
|
||||
* Gets the extended state variables.
|
||||
*
|
||||
* @return the extended state variables
|
||||
*/
|
||||
Map<String, Object> getVariables();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine;
|
||||
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
/**
|
||||
* {@code StateContext} is representing a current context used in
|
||||
* {@link Transition}s, {@link Action}s and {@link Guard}s order to get access
|
||||
* to event headers and {@link ExtendedState}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public interface StateContext {
|
||||
|
||||
/**
|
||||
* Gets the event message headers.
|
||||
*
|
||||
* @return the event message headers
|
||||
*/
|
||||
MessageHeaders getMessageHeaders();
|
||||
|
||||
/**
|
||||
* Gets the state machine extended state.
|
||||
*
|
||||
* @return the state machine extended state
|
||||
*/
|
||||
ExtendedState getExtendedState();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine;
|
||||
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.statemachine.listener.StateMachineListener;
|
||||
|
||||
/**
|
||||
* {@code StateMachine} provides an APIs for generic finite state machine needed
|
||||
* for basic operations like working with states, events and a lifecycle.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public interface StateMachine<S, E> {
|
||||
|
||||
/**
|
||||
* Gets the initial state {@code S}.
|
||||
*
|
||||
* @return initial state
|
||||
*/
|
||||
S getInitialState();
|
||||
|
||||
/**
|
||||
* Gets the current state {@code S}.
|
||||
*
|
||||
* @return current state
|
||||
*/
|
||||
S getState();
|
||||
|
||||
/**
|
||||
* Start the state machine.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Send an event {@code E} wrapped with a {@link Message} to the state
|
||||
* machine.
|
||||
*
|
||||
* @param event the wrapped event to send
|
||||
*/
|
||||
void sendEvent(Message<E> event);
|
||||
|
||||
/**
|
||||
* Send an event {@code E} to the state machine.
|
||||
*
|
||||
* @param event the event to send
|
||||
*/
|
||||
void sendEvent(E event);
|
||||
|
||||
/**
|
||||
* Adds the state listener.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
void addStateListener(StateMachineListener<S, E> listener);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine;
|
||||
|
||||
/**
|
||||
* Various constants used in state machine lib.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public abstract class StateMachineSystemConstants {
|
||||
|
||||
/** Default bean id for state machine. */
|
||||
public static final String DEFAULT_ID_STATEMACHINE = "stateMachine";
|
||||
|
||||
/** Default bean id for state machine factory. */
|
||||
public static final String DEFAULT_ID_STATEMACHINEFACTORY = "stateMachineFactory";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.action;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
|
||||
/**
|
||||
* Generic strategy interface used by a state machine to respond
|
||||
* events by executing an {@code Action} with a {@link StateContext}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public interface Action {
|
||||
|
||||
/**
|
||||
* Execute action with a {@link StateContext}.
|
||||
*
|
||||
* @param context the state context
|
||||
*/
|
||||
void execute(StateContext context);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface OnTransition {
|
||||
|
||||
String source() default "";
|
||||
|
||||
String target() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
@Component
|
||||
public @interface WithStateMachine {
|
||||
|
||||
String name() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.statemachine.StateMachineSystemConstants;
|
||||
import org.springframework.statemachine.config.common.annotation.EnableAnnotationConfiguration;
|
||||
import org.springframework.statemachine.config.common.annotation.configuration.ObjectPostProcessorConfiguration;
|
||||
import org.springframework.statemachine.config.configuration.StateMachineConfiguration;
|
||||
|
||||
/**
|
||||
* Example annotation which imports @{@link Configuration}s.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@EnableAnnotationConfiguration
|
||||
@Import({StateMachineConfiguration.class,ObjectPostProcessorConfiguration.class})
|
||||
public @interface EnableStateMachine {
|
||||
|
||||
/**
|
||||
* The name of bean, or if plural, aliases for bean created based on this
|
||||
* annotation. If left unspecified bean name will be autogenerated.
|
||||
*
|
||||
* @see Bean#name()
|
||||
* @return the array if names or empty as default
|
||||
*/
|
||||
String[] name() default {StateMachineSystemConstants.DEFAULT_ID_STATEMACHINE};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.statemachine.StateMachineSystemConstants;
|
||||
import org.springframework.statemachine.config.common.annotation.EnableAnnotationConfiguration;
|
||||
import org.springframework.statemachine.config.common.annotation.configuration.ObjectPostProcessorConfiguration;
|
||||
import org.springframework.statemachine.config.configuration.StateMachineFactoryConfiguration;
|
||||
|
||||
/**
|
||||
* Example annotation which imports @{@link Configuration}s.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@EnableAnnotationConfiguration
|
||||
@Import({StateMachineFactoryConfiguration.class,ObjectPostProcessorConfiguration.class})
|
||||
public @interface EnableStateMachineFactory {
|
||||
|
||||
/**
|
||||
* The name of bean, or if plural, aliases for bean created based on this
|
||||
* annotation. If left unspecified bean name will be autogenerated.
|
||||
*
|
||||
* @see Bean#name()
|
||||
* @return the array if names or empty as default
|
||||
*/
|
||||
String[] name() default {StateMachineSystemConstants.DEFAULT_ID_STATEMACHINEFACTORY};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config;
|
||||
|
||||
public class EnumStateMachineConfigurerAdapter<S extends Enum<S>, E extends Enum<E>> extends StateMachineConfigurerAdapter<S, E> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.statemachine.EnumStateMachine;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitions;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates.StateData;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitions.TransitionData;
|
||||
import org.springframework.statemachine.state.EnumState;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.support.LifecycleObjectSupport;
|
||||
import org.springframework.statemachine.transition.DefaultExternalTransition;
|
||||
import org.springframework.statemachine.transition.DefaultInternalTransition;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
import org.springframework.statemachine.transition.TransitionKind;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class EnumStateMachineFactory<S extends Enum<S>, E extends Enum<E>> extends LifecycleObjectSupport implements
|
||||
StateMachineFactory<State<S, E>, E> {
|
||||
|
||||
private final StateMachineTransitions<S, E> stateMachineTransitions;
|
||||
|
||||
private final StateMachineStates<S, E> stateMachineStates;
|
||||
|
||||
/**
|
||||
* Instantiates a new enum state machine factory.
|
||||
*
|
||||
* @param stateMachineTransitions the state machine transitions
|
||||
* @param stateMachineStates the state machine states
|
||||
*/
|
||||
public EnumStateMachineFactory(StateMachineTransitions<S, E> stateMachineTransitions,
|
||||
StateMachineStates<S, E> stateMachineStates) {
|
||||
this.stateMachineTransitions = stateMachineTransitions;
|
||||
this.stateMachineStates = stateMachineStates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachine<State<S, E>, E> getStateMachine() {
|
||||
return stateMachine();
|
||||
}
|
||||
|
||||
public StateMachine<State<S, E>, E> stateMachine() {
|
||||
Map<S, State<S, E>> stateMap = new HashMap<S, State<S, E>>();
|
||||
for (StateData<S, E> stateData : stateMachineStates.getStates()) {
|
||||
stateMap.put(stateData.getState(), new EnumState<S, E>(stateData.getState(), stateData.getDeferred(),
|
||||
stateData.getEntryActions(), stateData.getExitActions()));
|
||||
}
|
||||
|
||||
Collection<Transition<S, E>> transitions = new ArrayList<Transition<S, E>>();
|
||||
for (TransitionData<S, E> transitionData : stateMachineTransitions.getTransitions()) {
|
||||
S source = transitionData.getSource();
|
||||
S target = transitionData.getTarget();
|
||||
E event = transitionData.getEvent();
|
||||
if (transitionData.getKind() == TransitionKind.EXTERNAL) {
|
||||
DefaultExternalTransition<S, E> transition = new DefaultExternalTransition<S, E>(stateMap.get(source),
|
||||
stateMap.get(target), transitionData.getActions(), event, transitionData.getGuard());
|
||||
transitions.add(transition);
|
||||
|
||||
} else if (transitionData.getKind() == TransitionKind.INTERNAL) {
|
||||
DefaultInternalTransition<S, E> transition = new DefaultInternalTransition<S, E>(stateMap.get(source),
|
||||
transitionData.getActions(), event, transitionData.getGuard());
|
||||
transitions.add(transition);
|
||||
}
|
||||
}
|
||||
|
||||
EnumStateMachine<S, E> machine = new EnumStateMachine<S, E>(stateMap.values(), transitions,
|
||||
stateMap.get(stateMachineStates.getInitialState()));
|
||||
machine.afterPropertiesSet();
|
||||
if (getBeanFactory() != null) {
|
||||
machine.setBeanFactory(getBeanFactory());
|
||||
}
|
||||
machine.setAutoStartup(isAutoStartup());
|
||||
machine.start();
|
||||
return machine;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config;
|
||||
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitions;
|
||||
|
||||
public class StateMachineConfig<S, E> {
|
||||
|
||||
public final StateMachineTransitions<S, E> transitions;
|
||||
|
||||
public final StateMachineStates<S, E> states;
|
||||
|
||||
public StateMachineConfig(StateMachineTransitions<S, E> transitions, StateMachineStates<S, E> states) {
|
||||
this.transitions = transitions;
|
||||
this.states = states;
|
||||
}
|
||||
|
||||
public StateMachineTransitions<S, E> getTransitions() {
|
||||
return transitions;
|
||||
}
|
||||
|
||||
public StateMachineStates<S, E> getStates() {
|
||||
return states;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config;
|
||||
|
||||
import org.springframework.statemachine.config.builders.StateMachineConfigBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationBuilder;
|
||||
import org.springframework.statemachine.config.common.annotation.ObjectPostProcessor;
|
||||
|
||||
public class StateMachineConfigurerAdapter<S, E> implements StateMachineConfigurer<S, E> {
|
||||
|
||||
private StateMachineTransitionBuilder<S, E> transitionBuilder;
|
||||
private StateMachineStateBuilder<S, E> stateBuilder;
|
||||
|
||||
@Override
|
||||
public final void init(StateMachineConfigBuilder<S, E> config) throws Exception {
|
||||
config.setSharedObject(StateMachineTransitionBuilder.class, getStateMachineTransitionBuilder());
|
||||
config.setSharedObject(StateMachineStateBuilder.class, getStateMachineStateBuilder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineConfigBuilder<S, E> config) throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateConfigurer<S, E> states) throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionConfigurer<S, E> transitions) throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAssignable(AnnotationBuilder<StateMachineConfig<S, E>> builder) {
|
||||
return builder instanceof StateMachineConfigBuilder;
|
||||
}
|
||||
|
||||
protected final StateMachineTransitionBuilder<S, E> getStateMachineTransitionBuilder() throws Exception {
|
||||
if (transitionBuilder != null) {
|
||||
return transitionBuilder;
|
||||
}
|
||||
transitionBuilder = new StateMachineTransitionBuilder<S, E>(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true);
|
||||
configure(transitionBuilder);
|
||||
return transitionBuilder;
|
||||
}
|
||||
|
||||
protected final StateMachineStateBuilder<S, E> getStateMachineStateBuilder() throws Exception {
|
||||
if (stateBuilder != null) {
|
||||
return stateBuilder;
|
||||
}
|
||||
stateBuilder = new StateMachineStateBuilder<S, E>(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR, true);
|
||||
configure(stateBuilder);
|
||||
return stateBuilder;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config;
|
||||
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
|
||||
public interface StateMachineFactory<S, E> {
|
||||
|
||||
StateMachine<S, E> getStateMachine();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.builders;
|
||||
|
||||
import org.springframework.statemachine.config.StateMachineConfig;
|
||||
import org.springframework.statemachine.config.common.annotation.AbstractConfiguredAnnotationBuilder;
|
||||
|
||||
public class StateMachineConfigBuilder<S, E>
|
||||
extends
|
||||
AbstractConfiguredAnnotationBuilder<StateMachineConfig<S, E>, StateMachineConfigBuilder<S, E>, StateMachineConfigBuilder<S, E>> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected StateMachineConfig<S, E> performBuild() throws Exception {
|
||||
StateMachineTransitionBuilder<?, ?> sharedObject = getSharedObject(StateMachineTransitionBuilder.class);
|
||||
StateMachineStateBuilder<?, ?> sharedObject2 = getSharedObject(StateMachineStateBuilder.class);
|
||||
StateMachineStates<S, E> states = (StateMachineStates<S, E>) sharedObject2.build();
|
||||
StateMachineTransitions<S, E> transitions = (StateMachineTransitions<S, E>) sharedObject.build();
|
||||
StateMachineConfig<S, E> bean = new StateMachineConfig<S, E>(transitions, states);
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.builders;
|
||||
|
||||
import org.springframework.statemachine.config.StateMachineConfig;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurer;
|
||||
|
||||
public interface StateMachineConfigurer<S, E> extends
|
||||
AnnotationConfigurer<StateMachineConfig<S, E>, StateMachineConfigBuilder<S, E>> {
|
||||
|
||||
void configure(StateMachineStateConfigurer<S, E> transitions) throws Exception;
|
||||
|
||||
void configure(StateMachineTransitionConfigurer<S, E> transitions) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.builders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates.StateData;
|
||||
import org.springframework.statemachine.config.common.annotation.AbstractConfiguredAnnotationBuilder;
|
||||
import org.springframework.statemachine.config.common.annotation.ObjectPostProcessor;
|
||||
import org.springframework.statemachine.config.configurers.DefaultStateConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.StateConfigurer;
|
||||
|
||||
public class StateMachineStateBuilder<S, E>
|
||||
extends AbstractConfiguredAnnotationBuilder<StateMachineStates<S, E>, StateMachineStateConfigurer<S, E>, StateMachineStateBuilder<S, E>>
|
||||
implements StateMachineStateConfigurer<S, E> {
|
||||
|
||||
private Collection<StateData<S, E>> states = new ArrayList<StateData<S, E>>();
|
||||
private S initialState;
|
||||
|
||||
public StateMachineStateBuilder() {
|
||||
super();
|
||||
}
|
||||
|
||||
public StateMachineStateBuilder(ObjectPostProcessor<Object> objectPostProcessor,
|
||||
boolean allowConfigurersOfSameType) {
|
||||
super(objectPostProcessor, allowConfigurersOfSameType);
|
||||
}
|
||||
|
||||
public StateMachineStateBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
super(objectPostProcessor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StateMachineStates<S, E> performBuild() throws Exception {
|
||||
StateMachineStates<S, E> bean = new StateMachineStates<S, E>(initialState, states);
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> withStates() throws Exception {
|
||||
return apply(new DefaultStateConfigurer<S, E>());
|
||||
}
|
||||
|
||||
public void add(Collection<StateData<S, E>> states) {
|
||||
this.states.addAll(states);
|
||||
}
|
||||
|
||||
public void setInitialState(S state) {
|
||||
this.initialState = state;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.builders;
|
||||
|
||||
import org.springframework.statemachine.config.configurers.StateConfigurer;
|
||||
|
||||
public interface StateMachineStateConfigurer<S, E> {
|
||||
|
||||
StateConfigurer<S, E> withStates() throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.builders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
|
||||
public class StateMachineStates<S, E> {
|
||||
|
||||
private Collection<StateData<S, E>> states;
|
||||
|
||||
private final S initialState;
|
||||
|
||||
public StateMachineStates(S initialState, Collection<StateData<S, E>> states) {
|
||||
this.states = states;
|
||||
this.initialState = initialState;
|
||||
}
|
||||
|
||||
public Collection<StateData<S, E>> getStates() {
|
||||
return states;
|
||||
}
|
||||
|
||||
public S getInitialState() {
|
||||
return initialState;
|
||||
}
|
||||
|
||||
public static class StateData<S, E> {
|
||||
private S state;
|
||||
private Collection<E> deferred;
|
||||
private Collection<Action> entryActions;
|
||||
private Collection<Action> exitActions;
|
||||
public StateData(S state, Collection<E> deferred) {
|
||||
this(state, deferred, null, null);
|
||||
}
|
||||
public StateData(S state, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
this.state = state;
|
||||
this.deferred = deferred;
|
||||
this.entryActions = entryActions;
|
||||
this.exitActions = exitActions;
|
||||
}
|
||||
public StateData(S state, E[] deferred) {
|
||||
this(state, deferred != null ? Arrays.asList(deferred) : new ArrayList<E>());
|
||||
}
|
||||
public S getState() {
|
||||
return state;
|
||||
}
|
||||
public Collection<E> getDeferred() {
|
||||
return deferred;
|
||||
}
|
||||
public Collection<Action> getEntryActions() {
|
||||
return entryActions;
|
||||
}
|
||||
public Collection<Action> getExitActions() {
|
||||
return exitActions;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.builders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitions.TransitionData;
|
||||
import org.springframework.statemachine.config.common.annotation.AbstractConfiguredAnnotationBuilder;
|
||||
import org.springframework.statemachine.config.common.annotation.ObjectPostProcessor;
|
||||
import org.springframework.statemachine.config.configurers.DefaultExternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.DefaultInternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.ExternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.InternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.transition.TransitionKind;
|
||||
|
||||
public class StateMachineTransitionBuilder<S, E>
|
||||
extends
|
||||
AbstractConfiguredAnnotationBuilder<StateMachineTransitions<S, E>, StateMachineTransitionConfigurer<S, E>, StateMachineTransitionBuilder<S, E>>
|
||||
implements StateMachineTransitionConfigurer<S, E> {
|
||||
|
||||
private Collection<TransitionData<S, E>> transitionData = new ArrayList<TransitionData<S, E>>();
|
||||
|
||||
public StateMachineTransitionBuilder() {
|
||||
super();
|
||||
}
|
||||
|
||||
public StateMachineTransitionBuilder(ObjectPostProcessor<Object> objectPostProcessor,
|
||||
boolean allowConfigurersOfSameType) {
|
||||
super(objectPostProcessor, allowConfigurersOfSameType);
|
||||
}
|
||||
|
||||
public StateMachineTransitionBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
super(objectPostProcessor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StateMachineTransitions<S, E> performBuild() throws Exception {
|
||||
StateMachineTransitions<S, E> bean = new StateMachineTransitions<S, E>(transitionData);
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalTransitionConfigurer<S, E> withExternal() throws Exception {
|
||||
return apply(new DefaultExternalTransitionConfigurer<S, E>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalTransitionConfigurer<S, E> withInternal() throws Exception {
|
||||
return apply(new DefaultInternalTransitionConfigurer<S, E>());
|
||||
}
|
||||
|
||||
public void add(S source, S target, E event, Collection<Action> actions, Guard guard, TransitionKind kind) {
|
||||
transitionData.add(new TransitionData<S, E>(source, target, event, actions, guard, kind));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.builders;
|
||||
|
||||
import org.springframework.statemachine.config.configurers.ExternalTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.configurers.InternalTransitionConfigurer;
|
||||
|
||||
public interface StateMachineTransitionConfigurer<S, E> {
|
||||
|
||||
ExternalTransitionConfigurer<S, E> withExternal() throws Exception;
|
||||
|
||||
InternalTransitionConfigurer<S, E> withInternal() throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.builders;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.transition.TransitionKind;
|
||||
|
||||
public class StateMachineTransitions<S, E> {
|
||||
|
||||
private Collection<TransitionData<S, E>> transitions;
|
||||
|
||||
public StateMachineTransitions(Collection<TransitionData<S, E>> transitions) {
|
||||
this.transitions = transitions;
|
||||
}
|
||||
|
||||
public Collection<TransitionData<S, E>> getTransitions() {
|
||||
return transitions;
|
||||
}
|
||||
|
||||
public static class TransitionData<S, E> {
|
||||
S source;
|
||||
S target;
|
||||
E event;
|
||||
Collection<Action> actions;
|
||||
Guard guard;
|
||||
TransitionKind kind;
|
||||
public TransitionData(S source, S target, E event, Collection<Action> actions, Guard guard, TransitionKind kind) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
this.event = event;
|
||||
this.actions = actions;
|
||||
this.guard = guard;
|
||||
this.kind = kind;
|
||||
}
|
||||
public S getSource() {
|
||||
return source;
|
||||
}
|
||||
public S getTarget() {
|
||||
return target;
|
||||
}
|
||||
public E getEvent() {
|
||||
return event;
|
||||
}
|
||||
public Collection<Action> getActions() {
|
||||
return actions;
|
||||
}
|
||||
public Guard getGuard() {
|
||||
return guard;
|
||||
}
|
||||
public TransitionKind getKind() {
|
||||
return kind;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* A base {@link AnnotationBuilder} that ensures the object being built is only
|
||||
* built one time.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <O> the type of Object that is being built
|
||||
*/
|
||||
public abstract class AbstractAnnotationBuilder<O> implements AnnotationBuilder<O> {
|
||||
|
||||
/** Flag tracking build */
|
||||
private AtomicBoolean building = new AtomicBoolean();
|
||||
|
||||
/** Built object is stored here */
|
||||
private O object;
|
||||
|
||||
@Override
|
||||
public final O build() throws Exception {
|
||||
if(building.compareAndSet(false, true)) {
|
||||
object = doBuild();
|
||||
return object;
|
||||
}
|
||||
throw new IllegalStateException("This object has already been built");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object that was built. If it has not been built yet an Exception
|
||||
* is thrown.
|
||||
*
|
||||
* @return the Object that was built
|
||||
*/
|
||||
public final O getObject() {
|
||||
if(!building.get()) {
|
||||
throw new IllegalStateException("This object has not been built");
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should implement this to perform the build.
|
||||
*
|
||||
* @return the object that should be returned by {@link #build()}.
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
protected abstract O doBuild() throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Base implementation of @{@link Configuration} class.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <O> The object that used builder returns
|
||||
* @param <B> The type of the builder
|
||||
*/
|
||||
public abstract class AbstractAnnotationConfiguration<B extends AnnotationBuilder<O>, O>
|
||||
implements ImportAware, BeanClassLoaderAware {
|
||||
|
||||
private List<AnnotationConfigurer<O,B>> configurers;
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
private AnnotationAttributes annotationAttributes;
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
Map<String, Object> enableConfigurationAttrMap =
|
||||
importMetadata.getAnnotationAttributes(EnableAnnotationConfiguration.class.getName());
|
||||
AnnotationAttributes enableConfigurationAttrs = AnnotationAttributes.fromMap(enableConfigurationAttrMap);
|
||||
if(enableConfigurationAttrs == null) {
|
||||
// search parent classes
|
||||
Class<?> currentClass = ClassUtils.resolveClassName(importMetadata.getClassName(), beanClassLoader);
|
||||
for(Class<?> classToInspect = currentClass ;classToInspect != null; classToInspect = classToInspect.getSuperclass()) {
|
||||
EnableAnnotationConfiguration enableConfigurationAnnotation =
|
||||
AnnotationUtils.findAnnotation(classToInspect, EnableAnnotationConfiguration.class);
|
||||
if(enableConfigurationAnnotation == null) {
|
||||
continue;
|
||||
}
|
||||
enableConfigurationAttrMap = AnnotationUtils
|
||||
.getAnnotationAttributes(enableConfigurationAnnotation);
|
||||
enableConfigurationAttrs = AnnotationAttributes.fromMap(enableConfigurationAttrMap);
|
||||
}
|
||||
}
|
||||
annotationAttributes = enableConfigurationAttrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configurers.
|
||||
*
|
||||
* @param configurers the configurers
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
@Autowired(required=false)
|
||||
public void setConfigurers(List<AnnotationConfigurer<O, B>> configurers) throws Exception {
|
||||
this.configurers = configurers;
|
||||
onConfigurers(configurers);
|
||||
}
|
||||
|
||||
public AnnotationAttributes getAnnotationAttributes() {
|
||||
return annotationAttributes;
|
||||
}
|
||||
|
||||
public List<AnnotationConfigurer<O, B>> getConfigurers() {
|
||||
return configurers;
|
||||
}
|
||||
|
||||
protected abstract void onConfigurers(List<AnnotationConfigurer<O, B>> configurers) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,531 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A base {@link AnnotationBuilder} that allows {@link AnnotationConfigurer}s to be
|
||||
* applied to it. This makes modifying the {@link AnnotationBuilder} a strategy
|
||||
* that can be customised and broken up into a number of
|
||||
* {@link AnnotationConfigurer} objects that have more specific goals than that
|
||||
* of the {@link AnnotationBuilder}.
|
||||
* <p>
|
||||
*
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <O> The object that this builder returns
|
||||
* @param <I> The interface of type B
|
||||
* @param <B> The type of this builder (that is returned by the base class)
|
||||
*/
|
||||
public abstract class AbstractConfiguredAnnotationBuilder<O,I,B extends AnnotationBuilder<O>>
|
||||
extends AbstractAnnotationBuilder<O> {
|
||||
|
||||
private final static Log log = LogFactory.getLog(AbstractConfiguredAnnotationBuilder.class);
|
||||
|
||||
/** Configurers which are added to this builder before the configure step */
|
||||
private final LinkedHashMap<Class<? extends AnnotationConfigurer<O, B>>, List<AnnotationConfigurer<O, B>>> mainConfigurers =
|
||||
new LinkedHashMap<Class<? extends AnnotationConfigurer<O, B>>, List<AnnotationConfigurer<O, B>>>();
|
||||
|
||||
/** Configurers which are added to this builder during the configuration phase */
|
||||
private final LinkedHashMap<Class<? extends AnnotationConfigurer<O, B>>, List<AnnotationConfigurer<O, B>>> postConfigurers =
|
||||
new LinkedHashMap<Class<? extends AnnotationConfigurer<O, B>>, List<AnnotationConfigurer<O, B>>>();
|
||||
|
||||
private final Map<Class<Object>, Object> sharedObjects = new HashMap<Class<Object>, Object>();
|
||||
|
||||
private final boolean allowConfigurersOfSameType;
|
||||
|
||||
/** Current state of this builder */
|
||||
private BuildState buildState = BuildState.UNBUILT;
|
||||
|
||||
private ObjectPostProcessor<Object> objectPostProcessor;
|
||||
|
||||
/**
|
||||
* Instantiates a new annotation builder.
|
||||
*/
|
||||
protected AbstractConfiguredAnnotationBuilder() {
|
||||
this(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new annotation builder.
|
||||
*
|
||||
* @param objectPostProcessor the object post processor
|
||||
*/
|
||||
protected AbstractConfiguredAnnotationBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
this(objectPostProcessor,false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new annotation builder.
|
||||
*
|
||||
* @param objectPostProcessor the object post processor
|
||||
* @param allowConfigurersOfSameType the allow configurers of same type
|
||||
*/
|
||||
protected AbstractConfiguredAnnotationBuilder(ObjectPostProcessor<Object> objectPostProcessor, boolean allowConfigurersOfSameType) {
|
||||
Assert.notNull(objectPostProcessor, "objectPostProcessor cannot be null");
|
||||
this.objectPostProcessor = objectPostProcessor;
|
||||
this.allowConfigurersOfSameType = allowConfigurersOfSameType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final O doBuild() throws Exception {
|
||||
synchronized (mainConfigurers) {
|
||||
buildState = BuildState.INITIALIZING_MAINS;
|
||||
beforeInit();
|
||||
initMainConfigurers();
|
||||
|
||||
buildState = BuildState.CONFIGURING_MAINS;
|
||||
beforeConfigureMains();
|
||||
configureMainConfigurers();
|
||||
|
||||
buildState = BuildState.CONFIGURING_POSTS;
|
||||
beforeConfigurePosts();
|
||||
configurePostConfigurers();
|
||||
|
||||
buildState = BuildState.BUILDING;
|
||||
O result = performBuild();
|
||||
|
||||
buildState = BuildState.BUILT;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #build()} and {@link #getObject()} but checks the state
|
||||
* to determine if {@link #build()} needs to be called first.
|
||||
*
|
||||
* @return the result of {@link #build()} or {@link #getObject()}. If an
|
||||
* error occurs while building, returns null.
|
||||
*/
|
||||
public O getOrBuild() {
|
||||
if (isUnbuilt()) {
|
||||
try {
|
||||
return build();
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to perform build. Returning null", e);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return getObject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a {@link AnnotationConfigurerAdapter} to this
|
||||
* {@link AnnotationBuilder} and invokes
|
||||
* {@link AnnotationConfigurerAdapter#setBuilder(AnnotationBuilder)}.
|
||||
*
|
||||
* @param configurer the configurer
|
||||
* @param <C> type of AnnotationConfigurer
|
||||
* @return Configurer passed as parameter
|
||||
* @throws Exception if error occurred
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends AnnotationConfigurerAdapter<O,I,B>> C apply(C configurer) throws Exception {
|
||||
add(configurer);
|
||||
configurer.addObjectPostProcessor(objectPostProcessor);
|
||||
configurer.setBuilder((B) this);
|
||||
return configurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #apply(AnnotationConfigurer)} but checks the state
|
||||
* to determine if {@link #apply(AnnotationConfigurer)} needs to be called first.
|
||||
*
|
||||
* @param configurer the configurer
|
||||
* @param <C> type of AnnotationConfigurer
|
||||
* @return Configurer passed as parameter
|
||||
* @throws Exception if error occurred
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends AnnotationConfigurerAdapter<O,I,B>> C getOrApply(C configurer) throws Exception {
|
||||
C existing = (C) getConfigurer(configurer.getClass());
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
return apply(configurer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a {@link AnnotationConfigurer} to this {@link AnnotationBuilder}
|
||||
* overriding any {@link AnnotationConfigurer} of the exact same class. Note
|
||||
* that object hierarchies are not considered.
|
||||
*
|
||||
* @param configurer the configurer
|
||||
* @param <C> type of AnnotationConfigurer
|
||||
* @return Configurer passed as parameter
|
||||
* @throws Exception if error occurred
|
||||
*/
|
||||
public <C extends AnnotationConfigurer<O, B>> C apply(C configurer) throws Exception {
|
||||
add(configurer);
|
||||
return configurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an object that is shared by multiple {@link AnnotationConfigurer}.
|
||||
*
|
||||
* @param sharedType the Class to key the shared object by.
|
||||
* @param object the Object to store
|
||||
* @param <C> type of share object
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C> void setSharedObject(Class<C> sharedType, C object) {
|
||||
this.sharedObjects.put((Class<Object>) sharedType, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a shared Object. Note that object hierarchies are not considered.
|
||||
*
|
||||
* @param sharedType the type of the shared Object
|
||||
* @param <C> type of share object
|
||||
* @return the shared Object or null if it is not found
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C> C getSharedObject(Class<C> sharedType) {
|
||||
return (C) this.sharedObjects.get(sharedType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the shared objects.
|
||||
*
|
||||
* @return Shared objects
|
||||
*/
|
||||
public Map<Class<Object>, Object> getSharedObjects() {
|
||||
return Collections.unmodifiableMap(this.sharedObjects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@link AnnotationConfigurer} ensuring that it is allowed and
|
||||
* invoking {@link AnnotationConfigurer#init(AnnotationBuilder)} immediately
|
||||
* if necessary.
|
||||
*
|
||||
* @param configurer the {@link AnnotationConfigurer} to add
|
||||
* @param <C> type of AnnotationConfigurer
|
||||
* @throws Exception if an error occurs
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <C extends AnnotationConfigurer<O, B>> void add(C configurer) throws Exception {
|
||||
Assert.notNull(configurer, "configurer cannot be null");
|
||||
|
||||
Class<? extends AnnotationConfigurer<O, B>> clazz =
|
||||
(Class<? extends AnnotationConfigurer<O, B>>) configurer.getClass();
|
||||
|
||||
if (!buildState.isConfigured()) {
|
||||
synchronized (mainConfigurers) {
|
||||
List<AnnotationConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.mainConfigurers.get(clazz) : null;
|
||||
if (configs == null) {
|
||||
configs = new ArrayList<AnnotationConfigurer<O, B>>(1);
|
||||
}
|
||||
configs.add(configurer);
|
||||
this.mainConfigurers.put(clazz, configs);
|
||||
if (buildState.isInitializing()) {
|
||||
configurer.init((B) this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
synchronized (postConfigurers) {
|
||||
List<AnnotationConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.postConfigurers.get(clazz) : null;
|
||||
if (configs == null) {
|
||||
configs = new ArrayList<AnnotationConfigurer<O, B>>(1);
|
||||
}
|
||||
configs.add(configurer);
|
||||
this.postConfigurers.put(clazz, configs);
|
||||
configurer.init((B) this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the {@link AnnotationConfigurer} instances by its class name or an
|
||||
* empty List if not found. Note that object hierarchies are not considered.
|
||||
*
|
||||
* @param clazz the {@link AnnotationConfigurer} class to look for
|
||||
* @param <C> type of AnnotationConfigurer
|
||||
* @return All configurers
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends AnnotationConfigurer<O, B>> List<C> getConfigurers(Class<C> clazz) {
|
||||
List<C> configs = (List<C>) this.mainConfigurers.get(clazz);
|
||||
if (configs == null) {
|
||||
return new ArrayList<C>();
|
||||
}
|
||||
return new ArrayList<C>(configs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all the {@link AnnotationConfigurer} instances by its class name or an
|
||||
* empty List if not found. Note that object hierarchies are not considered.
|
||||
*
|
||||
* @param clazz the {@link AnnotationConfigurer} class to look for
|
||||
* @param <C> type of AnnotationConfigurer
|
||||
* @return Empty list of configurers
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends AnnotationConfigurer<O, B>> List<C> removeConfigurers(Class<C> clazz) {
|
||||
List<C> configs = (List<C>) this.mainConfigurers.remove(clazz);
|
||||
if (configs == null) {
|
||||
return new ArrayList<C>();
|
||||
}
|
||||
return new ArrayList<C>(configs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link AnnotationConfigurer} by its class name or
|
||||
* <code>null</code> if not found. Note that object hierarchies are not
|
||||
* considered.
|
||||
*
|
||||
* @param clazz the configurer class type
|
||||
* @param <C> type of AnnotationConfigurer
|
||||
* @return Matched configurers
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends AnnotationConfigurer<O, B>> C getConfigurer(Class<C> clazz) {
|
||||
List<AnnotationConfigurer<O, B>> configs = this.mainConfigurers.get(clazz);
|
||||
if (configs == null) {
|
||||
return null;
|
||||
}
|
||||
if (configs.size() != 1) {
|
||||
throw new IllegalStateException("Only one configurer expected for type " + clazz + ", but got " + configs);
|
||||
}
|
||||
return (C) configs.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes and returns the {@link AnnotationConfigurer} by its class name or
|
||||
* <code>null</code> if not found. Note that object hierarchies are not
|
||||
* considered.
|
||||
*
|
||||
* @param clazz the configurer class type
|
||||
* @param <C> type of AnnotationConfigurer
|
||||
* @return Matched configurers
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C extends AnnotationConfigurer<O, B>> C removeConfigurer(Class<C> clazz) {
|
||||
List<AnnotationConfigurer<O, B>> configs = this.mainConfigurers.remove(clazz);
|
||||
if (configs == null) {
|
||||
return null;
|
||||
}
|
||||
if (configs.size() != 1) {
|
||||
throw new IllegalStateException("Only one configurer expected for type " + clazz + ", but got " + configs);
|
||||
}
|
||||
return (C) configs.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link ObjectPostProcessor} to use.
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} to use. Cannot be null
|
||||
* @return the {@link AnnotationBuilder} for further customizations
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public O objectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
|
||||
Assert.notNull(objectPostProcessor,"objectPostProcessor cannot be null");
|
||||
this.objectPostProcessor = objectPostProcessor;
|
||||
return (O) this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs post processing of an object. The default is to delegate to the
|
||||
* {@link ObjectPostProcessor}.
|
||||
*
|
||||
* @param object the Object to post process
|
||||
* @param <P> type of processed object
|
||||
* @return the possibly modified Object to use
|
||||
*/
|
||||
protected <P> P postProcess(P object) {
|
||||
return (P) this.objectPostProcessor.postProcess(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked prior to invoking each
|
||||
* {@link AnnotationConfigurer#init(AnnotationBuilder)} method. Subclasses may
|
||||
* override this method to hook into the lifecycle without using a
|
||||
* {@link AnnotationConfigurer}.
|
||||
*
|
||||
* @throws Exception if error occurred
|
||||
*/
|
||||
protected void beforeInit() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked prior to invoking each main
|
||||
* {@link AnnotationConfigurer#configure(AnnotationBuilder)} method.
|
||||
* Subclasses may override this method to hook into the lifecycle without
|
||||
* using a {@link AnnotationConfigurer}.
|
||||
*
|
||||
* @throws Exception if error occurred
|
||||
*/
|
||||
protected void beforeConfigureMains() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked prior to invoking each post
|
||||
* {@link AnnotationConfigurer#configure(AnnotationBuilder)} method.
|
||||
* Subclasses may override this method to hook into the lifecycle without
|
||||
* using a {@link AnnotationConfigurer}.
|
||||
*
|
||||
* @throws Exception if error occurred
|
||||
*/
|
||||
protected void beforeConfigurePosts() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must implement this method to build the object that is being returned.
|
||||
*
|
||||
* @return Object build by this builder
|
||||
* @throws Exception if error occurred
|
||||
*/
|
||||
protected abstract O performBuild() throws Exception;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void initMainConfigurers() throws Exception {
|
||||
for (AnnotationConfigurer<O, B> configurer : getMainConfigurers()) {
|
||||
configurer.init((B) this);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void configureMainConfigurers() throws Exception {
|
||||
for (AnnotationConfigurer<O, B> configurer : getMainConfigurers()) {
|
||||
configurer.configure((B) this);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void configurePostConfigurers() throws Exception {
|
||||
for (AnnotationConfigurer<O, B> configurer : getPostConfigurers()) {
|
||||
configurer.configure((B) this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all configurers.
|
||||
*
|
||||
* @return the configurers
|
||||
*/
|
||||
private Collection<AnnotationConfigurer<O, B>> getMainConfigurers() {
|
||||
List<AnnotationConfigurer<O, B>> result = new ArrayList<AnnotationConfigurer<O, B>>();
|
||||
for (List<AnnotationConfigurer<O, B>> configs : this.mainConfigurers.values()) {
|
||||
result.addAll(configs);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Collection<AnnotationConfigurer<O, B>> getPostConfigurers() {
|
||||
List<AnnotationConfigurer<O, B>> result = new ArrayList<AnnotationConfigurer<O, B>>();
|
||||
for (List<AnnotationConfigurer<O, B>> configs : this.postConfigurers.values()) {
|
||||
result.addAll(configs);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the object is unbuilt.
|
||||
*
|
||||
* @return true, if unbuilt else false
|
||||
*/
|
||||
private boolean isUnbuilt() {
|
||||
synchronized (mainConfigurers) {
|
||||
return buildState == BuildState.UNBUILT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The build state for the application
|
||||
*/
|
||||
private static enum BuildState {
|
||||
|
||||
/**
|
||||
* This is the state before the {@link AnnotationBuilder#build()} is invoked
|
||||
*/
|
||||
UNBUILT(0),
|
||||
|
||||
/**
|
||||
* The state from when {@link AnnotationBuilder#build()} is first invoked until
|
||||
* all the {@link AnnotationConfigurer#init(AnnotationBuilder)} methods have
|
||||
* been invoked.
|
||||
*/
|
||||
INITIALIZING_MAINS(1),
|
||||
|
||||
/**
|
||||
* The state from after all main
|
||||
* {@link AnnotationConfigurer#init(AnnotationBuilder)}
|
||||
* have been invoked until after all the
|
||||
* {@link AnnotationConfigurer#configure(AnnotationBuilder)}
|
||||
* methods have been invoked.
|
||||
*/
|
||||
CONFIGURING_MAINS(2),
|
||||
|
||||
/**
|
||||
* The state from after all post
|
||||
* {@link AnnotationConfigurer#init(AnnotationBuilder)}
|
||||
* have been invoked until after all the
|
||||
* {@link AnnotationConfigurer#configure(AnnotationBuilder)}
|
||||
* methods have been invoked.
|
||||
*/
|
||||
CONFIGURING_POSTS(3),
|
||||
|
||||
/**
|
||||
* From the point after all the
|
||||
* {@link AnnotationConfigurer#configure(AnnotationBuilder)}
|
||||
* have completed to just after
|
||||
* {@link AbstractConfiguredAnnotationBuilder#performBuild()}.
|
||||
*/
|
||||
BUILDING(4),
|
||||
|
||||
/**
|
||||
* After the object has been completely built.
|
||||
*/
|
||||
BUILT(5);
|
||||
|
||||
private final int order;
|
||||
|
||||
BuildState(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is initializing.
|
||||
*
|
||||
* @return true, if is initializing
|
||||
*/
|
||||
public boolean isInitializing() {
|
||||
return INITIALIZING_MAINS.order == order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the state is CONFIGURING or later
|
||||
*
|
||||
* @return true, if configured
|
||||
*/
|
||||
public boolean isConfigured() {
|
||||
return order >= CONFIGURING_MAINS.order;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Base class for {@link Configuration} which works on a bean definition level
|
||||
* relying on {@link ImportBeanDefinitionRegistrar} phase to register beans.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <O> The object that used builder returns
|
||||
* @param <B> The type of the builder
|
||||
*/
|
||||
public abstract class AbstractImportingAnnotationConfiguration<B extends AnnotationBuilder<O>, O> implements
|
||||
ImportBeanDefinitionRegistrar, BeanFactoryAware, EnvironmentAware {
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private Environment environment;
|
||||
|
||||
private final BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||
Class<?> annotationType = getAnnotation();
|
||||
AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(
|
||||
annotationType.getName(), false));
|
||||
String[] names = attributes.getStringArray("name");
|
||||
|
||||
BeanDefinition beanDefinition;
|
||||
try {
|
||||
beanDefinition = buildBeanDefinition();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error with onConfigurers", e);
|
||||
}
|
||||
|
||||
if (ObjectUtils.isEmpty(names)) {
|
||||
// ok, name(s) not given, generate one
|
||||
names = new String[] { beanNameGenerator.generateBeanName(beanDefinition, registry) };
|
||||
}
|
||||
|
||||
registry.registerBeanDefinition(names[0], beanDefinition);
|
||||
if (names.length > 1) {
|
||||
for (int i = 1; i < names.length; i++) {
|
||||
registry.registerAlias(names[0], names[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract static class BeanDelegatingFactoryBean<B extends AnnotationBuilder<O>, O>
|
||||
implements FactoryBean<O>, InitializingBean {
|
||||
|
||||
private final B builder;
|
||||
|
||||
private O object;
|
||||
|
||||
private List<AnnotationConfigurer<O, B>> configurers;
|
||||
|
||||
public BeanDelegatingFactoryBean(B builder){
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Class<O> getObjectType();
|
||||
|
||||
@Override
|
||||
public O getObject() throws Exception {
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void afterPropertiesSet() throws Exception {
|
||||
// for (AnnotationConfigurer<O, B> configurer : configurers) {
|
||||
// if (configurer.isAssignable(builder)) {
|
||||
// // we need builder.apply(configurer);
|
||||
//// builder.
|
||||
// }
|
||||
// }
|
||||
// // should be getOrBuild???
|
||||
// object = builder.build();
|
||||
// }
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setConfigurers(List<AnnotationConfigurer<O, B>> configurers) {
|
||||
this.configurers = configurers;
|
||||
}
|
||||
|
||||
public B getBuilder() {
|
||||
return builder;
|
||||
}
|
||||
|
||||
public List<AnnotationConfigurer<O, B>> getConfigurers() {
|
||||
return configurers;
|
||||
}
|
||||
|
||||
protected void setObject(O object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
Assert.isInstanceOf(ListableBeanFactory.class, beanFactory,
|
||||
"beanFactory be of type ListableBeanFactory but was " + beanFactory);
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to get a bean definition to register.
|
||||
*
|
||||
* @return the bean definition to register
|
||||
* @throws Exception if error occurred
|
||||
*/
|
||||
protected abstract BeanDefinition buildBeanDefinition() throws Exception;
|
||||
|
||||
/**
|
||||
* Gets the annotation specific for this configurer.
|
||||
*
|
||||
* @return the annotation
|
||||
*/
|
||||
protected abstract Class<? extends Annotation> getAnnotation();
|
||||
|
||||
/**
|
||||
* Gets the bean factory.
|
||||
*
|
||||
* @return the bean factory
|
||||
*/
|
||||
protected BeanFactory getBeanFactory() {
|
||||
return beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the environment.
|
||||
*
|
||||
* @return the environment
|
||||
*/
|
||||
protected Environment getEnvironment() {
|
||||
return environment;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation;
|
||||
|
||||
/**
|
||||
* Interface for building an {@link Object}.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <O> The type of the Object being built
|
||||
*/
|
||||
public interface AnnotationBuilder<O> {
|
||||
|
||||
/**
|
||||
* Builds the object and returns it or null.
|
||||
*
|
||||
* @return the Object to be built or null if the implementation allows it.
|
||||
* @throws Exception if an error occurred when building the Object
|
||||
*/
|
||||
O build() throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation;
|
||||
|
||||
/**
|
||||
* Allows for configuring an {@link AnnotationBuilder}. All
|
||||
* {@link AnnotationConfigurer}s first have their {@link #init(AnnotationBuilder)}
|
||||
* method invoked. After all {@link #init(AnnotationBuilder)} methods have been
|
||||
* invoked, each {@link #configure(AnnotationBuilder)} method is invoked.
|
||||
*
|
||||
* @see AbstractConfiguredAnnotationBuilder
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <O> The object being built by the {@link AnnotationBuilder} B
|
||||
* @param <B> The {@link AnnotationBuilder} that builds objects of type O. This is
|
||||
* also the {@link AnnotationBuilder} that is being configured.
|
||||
*/
|
||||
public interface AnnotationConfigurer<O, B extends AnnotationBuilder<O>> {
|
||||
|
||||
/**
|
||||
* Initialise the {@link AnnotationBuilder}. Here only shared state should be
|
||||
* created and modified, but not properties on the {@link AnnotationBuilder}
|
||||
* used for building the object. This ensures that the
|
||||
* {@link #configure(AnnotationBuilder)} method uses the correct shared
|
||||
* objects when building.
|
||||
*
|
||||
* @param builder the builder
|
||||
* @throws Exception if error occurred
|
||||
*/
|
||||
void init(B builder) throws Exception;
|
||||
|
||||
/**
|
||||
* Configure the {@link AnnotationBuilder} by setting the necessary properties
|
||||
* on the {@link AnnotationBuilder}.
|
||||
*
|
||||
* @param builder the builder
|
||||
* @throws Exception if error occurred
|
||||
*/
|
||||
void configure(B builder) throws Exception;
|
||||
|
||||
boolean isAssignable(AnnotationBuilder<O> builder);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
|
||||
/**
|
||||
* A base class for {@link AnnotationConfigurer} that allows subclasses to only
|
||||
* implement the methods they are interested in. It also provides a mechanism
|
||||
* for using the {@link AnnotationConfigurer} and when done gaining access to the
|
||||
* {@link AnnotationBuilder} that is being configured.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <O> The Object being built by B
|
||||
* @param <I> The interface of type B
|
||||
* @param <B> The Builder that is building O and is configured by {@link AnnotationConfigurerAdapter}
|
||||
*/
|
||||
public abstract class AnnotationConfigurerAdapter<O,I,B extends AnnotationBuilder<O>>
|
||||
implements AnnotationConfigurer<O,B> {
|
||||
|
||||
private B builder;
|
||||
|
||||
private CompositeObjectPostProcessor objectPostProcessor = new CompositeObjectPostProcessor();
|
||||
|
||||
@Override
|
||||
public void init(B builder) throws Exception {}
|
||||
|
||||
@Override
|
||||
public void configure(B builder) throws Exception {}
|
||||
|
||||
/**
|
||||
* Return the {@link AnnotationBuilder} when done using the
|
||||
* {@link AnnotationConfigurer}. This is useful for method chaining.
|
||||
*
|
||||
* @return the {@link AnnotationBuilder}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public I and() {
|
||||
// we're either casting to itself or its interface
|
||||
return (I) getBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link AnnotationBuilder}. Cannot be null.
|
||||
*
|
||||
* @return the {@link AnnotationBuilder}
|
||||
* @throws IllegalStateException if AnnotationBuilder is null
|
||||
*/
|
||||
protected final B getBuilder() {
|
||||
if(builder == null) {
|
||||
throw new IllegalStateException("annotationBuilder cannot be null");
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an {@link ObjectPostProcessor} to be used for this adapter. The
|
||||
* default implementation does nothing to the object.
|
||||
*
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} to use
|
||||
*/
|
||||
public void addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
|
||||
this.objectPostProcessor.addObjectPostProcessor(objectPostProcessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AnnotationBuilder} to be used. This is automatically set
|
||||
* when using
|
||||
* {@link AbstractConfiguredAnnotationBuilder#apply(AnnotationConfigurerAdapter)}
|
||||
*
|
||||
* @param builder the {@link AnnotationBuilder} to set
|
||||
*/
|
||||
public void setBuilder(B builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link ObjectPostProcessor} that delegates work to numerous
|
||||
* {@link ObjectPostProcessor} implementations.
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private static final class CompositeObjectPostProcessor implements ObjectPostProcessor<Object> {
|
||||
|
||||
private List<ObjectPostProcessor<? extends Object>> postProcessors = new ArrayList<ObjectPostProcessor<?>>();
|
||||
|
||||
@Override
|
||||
public Object postProcess(Object object) {
|
||||
for(ObjectPostProcessor opp : postProcessors) {
|
||||
Class<?> oppClass = opp.getClass();
|
||||
Class<?> oppType = GenericTypeResolver.resolveTypeArgument(oppClass,ObjectPostProcessor.class);
|
||||
if(oppType == null || oppType.isAssignableFrom(object.getClass())) {
|
||||
object = opp.postProcess(object);
|
||||
}
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an {@link ObjectPostProcessor} to use
|
||||
*
|
||||
* @param objectPostProcessor the {@link ObjectPostProcessor} to add
|
||||
* @return true if the {@link ObjectPostProcessor} was added, else false
|
||||
*/
|
||||
private boolean addObjectPostProcessor(ObjectPostProcessor<? extends Object> objectPostProcessor) {
|
||||
return this.postProcessors.add(objectPostProcessor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAssignable(AnnotationBuilder<O> builder) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation;
|
||||
|
||||
/**
|
||||
* Interface for wrapping a return type from {@link AnnotationConfigurer}
|
||||
* into {@link AnnotationBuilder}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <I> The parent return type of the configurer.
|
||||
*/
|
||||
public interface AnnotationConfigurerBuilder<I> {
|
||||
|
||||
/**
|
||||
* Get a parent {@link AnnotationBuilder} working
|
||||
* with a {@link AnnotationConfigurer}.
|
||||
* @return The parent {@link AnnotationBuilder}
|
||||
*/
|
||||
I and();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Base annotation used in JavaConfig order to enable
|
||||
* some base functionality.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
public @interface EnableAnnotationConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation;
|
||||
|
||||
import org.springframework.beans.factory.Aware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Allows initialization of Objects. Typically this is used to call the
|
||||
* {@link Aware} methods, {@link InitializingBean#afterPropertiesSet()}, and
|
||||
* ensure that {@link DisposableBean#destroy()} has been invoked.
|
||||
*
|
||||
* @param <T> the bound of the types of Objects this {@link ObjectPostProcessor} supports.
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public interface ObjectPostProcessor<T> {
|
||||
|
||||
/**
|
||||
* Initialize the object possibly returning a modified instance that should
|
||||
* be used instead.
|
||||
*
|
||||
* @param object the object to initialize
|
||||
* @param <O> the type of a processed object
|
||||
* @return the initialized version of the object
|
||||
*/
|
||||
<O extends T> O postProcess(O object);
|
||||
|
||||
/**
|
||||
* A do nothing implementation of the {@link ObjectPostProcessor}
|
||||
*/
|
||||
ObjectPostProcessor<Object> QUIESCENT_POSTPROCESSOR = new ObjectPostProcessor<Object>() {
|
||||
@Override
|
||||
public <T> T postProcess(T object) {
|
||||
return object;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation.configuration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.statemachine.config.common.annotation.ObjectPostProcessor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Post processor handling lifecycle methods of
|
||||
* POJOs created from builder/configurer.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
final class AutowireBeanFactoryObjectPostProcessor implements ObjectPostProcessor<Object>, DisposableBean, SmartLifecycle {
|
||||
|
||||
private final static Log log = LogFactory.getLog(AutowireBeanFactoryObjectPostProcessor.class);
|
||||
|
||||
private final AutowireCapableBeanFactory autowireBeanFactory;
|
||||
private final List<DisposableBean> disposableBeans = new ArrayList<DisposableBean>();
|
||||
private final List<Lifecycle> lifecycleBeans = new ArrayList<Lifecycle>();
|
||||
|
||||
private boolean running;
|
||||
|
||||
/**
|
||||
* Instantiates a new autowire bean factory object post processor.
|
||||
*
|
||||
* @param autowireBeanFactory the autowire bean factory
|
||||
*/
|
||||
public AutowireBeanFactoryObjectPostProcessor(AutowireCapableBeanFactory autowireBeanFactory) {
|
||||
Assert.notNull(autowireBeanFactory, "autowireBeanFactory cannot be null");
|
||||
this.autowireBeanFactory = autowireBeanFactory;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T postProcess(T object) {
|
||||
T result = (T) autowireBeanFactory.initializeBean(object, null);
|
||||
if(result instanceof DisposableBean) {
|
||||
disposableBeans.add((DisposableBean) result);
|
||||
}
|
||||
if(result instanceof Lifecycle) {
|
||||
lifecycleBeans.add((Lifecycle) result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
for(DisposableBean disposable : disposableBeans) {
|
||||
try {
|
||||
disposable.destroy();
|
||||
} catch(Exception error) {
|
||||
log.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
running = true;
|
||||
for (Lifecycle bean : lifecycleBeans) {
|
||||
bean.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
for (Lifecycle bean : lifecycleBeans) {
|
||||
bean.stop();
|
||||
}
|
||||
running = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return running;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPhase() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoStartup() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(Runnable callback) {
|
||||
stop();
|
||||
callback.run();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation.configuration;
|
||||
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.config.common.annotation.EnableAnnotationConfiguration;
|
||||
import org.springframework.statemachine.config.common.annotation.ObjectPostProcessor;
|
||||
|
||||
/**
|
||||
* Spring {@link Configuration} that exports the default
|
||||
* {@link ObjectPostProcessor}. This class is not intended to be imported
|
||||
* manually rather it is imported automatically when using {@link EnableAnnotationConfiguration}
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @see EnableAnnotationConfiguration
|
||||
*/
|
||||
@Configuration
|
||||
public class ObjectPostProcessorConfiguration {
|
||||
|
||||
@Bean
|
||||
public ObjectPostProcessor<Object> objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
|
||||
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation.configurers;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationBuilder;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.statemachine.config.common.annotation.AnnotationConfigurer AnnotationConfigurer}
|
||||
* which knows how to handle configuring a {@link Properties}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <O> The Object being built by B
|
||||
* @param <I> The type of interface or builder itself returned by the configurer
|
||||
* @param <B> The Builder that is building O and is configured by {@link AnnotationConfigurerAdapter}
|
||||
*/
|
||||
public class DefaultPropertiesConfigurer<O,I,B extends AnnotationBuilder<O>>
|
||||
extends AnnotationConfigurerAdapter<O,I,B> implements PropertiesConfigurer<I> {
|
||||
|
||||
private Properties properties = new Properties();
|
||||
|
||||
/**
|
||||
* Adds a {@link Properties} to this builder.
|
||||
*
|
||||
* @param properties the properties
|
||||
* @return the {@link PropertiesConfigurer} for chaining
|
||||
*/
|
||||
@Override
|
||||
public PropertiesConfigurer<I> properties(Properties properties) {
|
||||
if (properties != null) {
|
||||
this.properties.putAll(properties);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertiesConfigurer<I> properties(Map<String, String> properties) {
|
||||
Properties props = new Properties();
|
||||
if (properties != null) {
|
||||
props.putAll(properties);
|
||||
}
|
||||
return properties(props);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a property to this builder.
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @return the {@link PropertiesConfigurer} for chaining
|
||||
*/
|
||||
@Override
|
||||
public PropertiesConfigurer<I> property(String key, String value) {
|
||||
properties.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Properties} configured for this builder.
|
||||
*
|
||||
* @return the properties
|
||||
*/
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(B builder) throws Exception {
|
||||
if (!configureProperties(builder, properties)) {
|
||||
if (builder instanceof PropertiesConfigurerAware) {
|
||||
((PropertiesConfigurerAware)builder).configureProperties(properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure properties. If this implementation is extended,
|
||||
* custom configure handling can be handled here.
|
||||
*
|
||||
* @param builder the builder
|
||||
* @param properties the properties
|
||||
* @return true, if properties configure is handled
|
||||
*/
|
||||
protected boolean configureProperties(B builder, Properties properties){
|
||||
return false;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation.configurers;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationBuilder;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurer;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* {@link AnnotationConfigurer} which knows how to handle
|
||||
* configuring a {@link Resource}s.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <O> The Object being built by B
|
||||
* @param <B> The Builder that is building O and is configured by {@link AnnotationConfigurerAdapter}
|
||||
* @param <I> The type of an interface of B
|
||||
*/
|
||||
public class DefaultResourceConfigurer<O,I,B extends AnnotationBuilder<O>>
|
||||
extends AnnotationConfigurerAdapter<O,I,B> implements ResourceConfigurer<I> {
|
||||
|
||||
private Set<Resource> resources = new HashSet<Resource>();
|
||||
private final DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
|
||||
@Override
|
||||
public void configure(B builder) throws Exception {
|
||||
if (!configureResources(builder, resources)) {
|
||||
if (builder instanceof ResourceConfigurerAware) {
|
||||
((ResourceConfigurerAware)builder).configureResources(resources);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link Set} of {@link Resource}s to this builder.
|
||||
*
|
||||
* @param resources the resources
|
||||
* @return the {@link ResourceConfigurer} for chaining
|
||||
*/
|
||||
@Override
|
||||
public ResourceConfigurer<I> resources(Set<Resource> resources) {
|
||||
this.resources.addAll(resources);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link Resource} to this builder.
|
||||
*
|
||||
* @param resource the resource
|
||||
* @return the {@link ResourceConfigurer} for chaining
|
||||
*/
|
||||
@Override
|
||||
public ResourceConfigurer<I> resource(Resource resource) {
|
||||
resources.add(resource);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link Resource} to this builder.
|
||||
*
|
||||
* @param resource the resource
|
||||
* @return the {@link ResourceConfigurer} for chaining
|
||||
*/
|
||||
@Override
|
||||
public ResourceConfigurer<I> resource(String resource) {
|
||||
resources.add(resourceLoader.getResource(resource));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link Resource}s to this builder.
|
||||
*
|
||||
* @param resources the resources
|
||||
* @return the {@link ResourceConfigurer} for chaining
|
||||
*/
|
||||
@Override
|
||||
public ResourceConfigurer<I> resources(List<String> resources) {
|
||||
if (resources != null) {
|
||||
for (String resource : resources) {
|
||||
resource(resource);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Resource}s configured for this builder.
|
||||
*
|
||||
* @return the resources
|
||||
*/
|
||||
public Set<Resource> getResources() {
|
||||
return resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure resources. If this implementation is extended,
|
||||
* custom configure handling can be handled here.
|
||||
*
|
||||
* @param builder the builder
|
||||
* @param resources the resources
|
||||
* @return true, if resources configure is handled
|
||||
*/
|
||||
protected boolean configureResources(B builder, Set<Resource> resources){
|
||||
return false;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation.configurers;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerBuilder;
|
||||
|
||||
/**
|
||||
* Interface for {@link DefaultPropertiesConfigurer} which act
|
||||
* as intermediate gatekeeper between a user and
|
||||
* an {@link org.springframework.statemachine.config.common.annotation.AnnotationConfigurer}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <I> The parent return type of the configurer.
|
||||
*/
|
||||
public interface PropertiesConfigurer<I> extends AnnotationConfigurerBuilder<I> {
|
||||
|
||||
PropertiesConfigurer<I> properties(Properties properties);
|
||||
|
||||
PropertiesConfigurer<I> properties(Map<String, String> properties);
|
||||
|
||||
PropertiesConfigurer<I> property(String key, String value);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation.configurers;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Interface for {@link org.springframework.statemachine.config.common.annotation.AnnotationBuilder AnnotationBuilder}
|
||||
* which wants to be aware of {@link Properties} configured by {@link DefaultPropertiesConfigurer}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public interface PropertiesConfigurerAware {
|
||||
|
||||
/**
|
||||
* Configure {@link Properties}.
|
||||
*
|
||||
* @param properties the properties
|
||||
*/
|
||||
void configureProperties(Properties properties);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation.configurers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerBuilder;
|
||||
|
||||
/**
|
||||
* Interface for {@link DefaultResourceConfigurer} which act
|
||||
* as intermediate gatekeeper between a user and
|
||||
* an {@link org.springframework.statemachine.config.common.annotation.AnnotationConfigurer}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <I> The parent return type of the configurer.
|
||||
*/
|
||||
public interface ResourceConfigurer<I> extends AnnotationConfigurerBuilder<I> {
|
||||
|
||||
ResourceConfigurer<I> resources(Set<Resource> resources);
|
||||
|
||||
ResourceConfigurer<I> resources(List<String> resources);
|
||||
|
||||
ResourceConfigurer<I> resource(Resource resource);
|
||||
|
||||
ResourceConfigurer<I> resource(String resource);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.common.annotation.configurers;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationBuilder;
|
||||
|
||||
/**
|
||||
* Interface for {@link AnnotationBuilder} which wants to be
|
||||
* aware of {@link Resource}s configured by {@link DefaultResourceConfigurer}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public interface ResourceConfigurerAware {
|
||||
|
||||
/**
|
||||
* Configure {@link Resource}s.
|
||||
*
|
||||
* @param resources the resources
|
||||
*/
|
||||
void configureResources(Set<Resource> resources);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package org.springframework.statemachine.config.configuration;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.config.EnableStateMachine;
|
||||
import org.springframework.statemachine.config.EnumStateMachineFactory;
|
||||
import org.springframework.statemachine.config.StateMachineConfig;
|
||||
import org.springframework.statemachine.config.builders.StateMachineConfigBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitions;
|
||||
import org.springframework.statemachine.config.common.annotation.AbstractImportingAnnotationConfiguration;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurer;
|
||||
import org.springframework.statemachine.state.State;
|
||||
|
||||
@Configuration
|
||||
public class StateMachineConfiguration<S extends Enum<S>, E extends Enum<E>> extends
|
||||
AbstractImportingAnnotationConfiguration<StateMachineConfigBuilder<S, E>, StateMachineConfig<S, E>> {
|
||||
|
||||
private final StateMachineConfigBuilder<S, E> builder = new StateMachineConfigBuilder<S, E>();
|
||||
|
||||
@Override
|
||||
protected BeanDefinition buildBeanDefinition() throws Exception {
|
||||
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(StateMachineDelegatingFactoryBean.class);
|
||||
beanDefinitionBuilder.addConstructorArgValue(builder);
|
||||
return beanDefinitionBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends Annotation> getAnnotation() {
|
||||
return EnableStateMachine.class;
|
||||
}
|
||||
|
||||
private static class StateMachineDelegatingFactoryBean<S extends Enum<S>, E extends Enum<E>> implements
|
||||
FactoryBean<StateMachine<State<S, E>, E>>, BeanFactoryAware, InitializingBean {
|
||||
|
||||
private final StateMachineConfigBuilder<S, E> builder;
|
||||
|
||||
private List<AnnotationConfigurer<StateMachineConfig<S, E>, StateMachineConfigBuilder<S, E>>> configurers;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private StateMachine<State<S, E>, E> stateMachine;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public StateMachineDelegatingFactoryBean(StateMachineConfigBuilder<S, E> builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachine<State<S, E>, E> getObject() throws Exception {
|
||||
return stateMachine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return StateMachine.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
for (AnnotationConfigurer<StateMachineConfig<S, E>, StateMachineConfigBuilder<S, E>> configurer : configurers) {
|
||||
builder.apply(configurer);
|
||||
}
|
||||
StateMachineConfig<S, E> stateMachineConfig = builder.getOrBuild();
|
||||
StateMachineTransitions<S, E> stateMachineTransitions = stateMachineConfig.getTransitions();
|
||||
StateMachineStates<S, E> stateMachineStates = stateMachineConfig.getStates();
|
||||
EnumStateMachineFactory<S,E> stateMachineFactory = new EnumStateMachineFactory<S, E>(stateMachineTransitions, stateMachineStates);
|
||||
stateMachineFactory.setBeanFactory(beanFactory);
|
||||
stateMachine = stateMachineFactory.getStateMachine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Autowired(required=false)
|
||||
protected void onConfigurers(
|
||||
List<AnnotationConfigurer<StateMachineConfig<S, E>, StateMachineConfigBuilder<S, E>>> configurers)
|
||||
throws Exception {
|
||||
this.configurers = configurers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package org.springframework.statemachine.config.configuration;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.statemachine.config.EnableStateMachineFactory;
|
||||
import org.springframework.statemachine.config.EnumStateMachineFactory;
|
||||
import org.springframework.statemachine.config.StateMachineConfig;
|
||||
import org.springframework.statemachine.config.StateMachineFactory;
|
||||
import org.springframework.statemachine.config.builders.StateMachineConfigBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitions;
|
||||
import org.springframework.statemachine.config.common.annotation.AbstractImportingAnnotationConfiguration;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurer;
|
||||
import org.springframework.statemachine.state.State;
|
||||
|
||||
@Configuration
|
||||
public class StateMachineFactoryConfiguration<S extends Enum<S>, E extends Enum<E>> extends
|
||||
AbstractImportingAnnotationConfiguration<StateMachineConfigBuilder<S, E>, StateMachineConfig<S, E>> {
|
||||
|
||||
private final StateMachineConfigBuilder<S, E> builder = new StateMachineConfigBuilder<S, E>();
|
||||
|
||||
@Override
|
||||
protected BeanDefinition buildBeanDefinition() throws Exception {
|
||||
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(StateMachineFactoryDelegatingFactoryBean.class);
|
||||
beanDefinitionBuilder.addConstructorArgValue(builder);
|
||||
return beanDefinitionBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends Annotation> getAnnotation() {
|
||||
return EnableStateMachineFactory.class;
|
||||
}
|
||||
|
||||
private static class StateMachineFactoryDelegatingFactoryBean<S extends Enum<S>, E extends Enum<E>> implements
|
||||
FactoryBean<StateMachineFactory<State<S, E>, E>>, BeanFactoryAware, InitializingBean {
|
||||
|
||||
private final StateMachineConfigBuilder<S, E> builder;
|
||||
|
||||
private List<AnnotationConfigurer<StateMachineConfig<S, E>, StateMachineConfigBuilder<S, E>>> configurers;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private StateMachineFactory<State<S, E>, E> stateMachineFactory;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public StateMachineFactoryDelegatingFactoryBean(StateMachineConfigBuilder<S, E> builder) {
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachineFactory<State<S, E>, E> getObject() throws Exception {
|
||||
return stateMachineFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return StateMachineFactory.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
for (AnnotationConfigurer<StateMachineConfig<S, E>, StateMachineConfigBuilder<S, E>> configurer : configurers) {
|
||||
builder.apply(configurer);
|
||||
}
|
||||
StateMachineConfig<S, E> stateMachineConfig = builder.getOrBuild();
|
||||
StateMachineTransitions<S, E> stateMachineTransitions = stateMachineConfig.getTransitions();
|
||||
StateMachineStates<S, E> stateMachineStates = stateMachineConfig.getStates();
|
||||
EnumStateMachineFactory<S,E> enumStateMachineFactory = new EnumStateMachineFactory<S, E>(stateMachineTransitions, stateMachineStates);
|
||||
enumStateMachineFactory.setBeanFactory(beanFactory);
|
||||
this.stateMachineFactory = enumStateMachineFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Autowired(required=false)
|
||||
protected void onConfigurers(
|
||||
List<AnnotationConfigurer<StateMachineConfig<S, E>, StateMachineConfigBuilder<S, E>>> configurers)
|
||||
throws Exception {
|
||||
this.configurers = configurers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.expression.spel.SpelCompilerMode;
|
||||
import org.springframework.expression.spel.SpelParserConfiguration;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitions;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerAdapter;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.guard.SpelExpressionGuard;
|
||||
import org.springframework.statemachine.transition.TransitionKind;
|
||||
|
||||
/**
|
||||
* Default implementation of a {@link ExternalTransitionConfigurer}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class DefaultExternalTransitionConfigurer<S, E>
|
||||
extends AnnotationConfigurerAdapter<StateMachineTransitions<S, E>, StateMachineTransitionConfigurer<S, E>, StateMachineTransitionBuilder<S, E>>
|
||||
implements ExternalTransitionConfigurer<S, E> {
|
||||
|
||||
private S source;
|
||||
|
||||
private S target;
|
||||
|
||||
private E event;
|
||||
|
||||
private Collection<Action> actions = new ArrayList<Action>();
|
||||
|
||||
private Guard guard;
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
builder.add(source, target, event, actions, guard, TransitionKind.EXTERNAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalTransitionConfigurer<S, E> source(S source) {
|
||||
this.source = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalTransitionConfigurer<S, E> target(S target) {
|
||||
this.target = target;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalTransitionConfigurer<S, E> event(E event) {
|
||||
this.event = event;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalTransitionConfigurer<S, E> action(Action action) {
|
||||
actions.add(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalTransitionConfigurer<S, E> guard(Guard guard) {
|
||||
this.guard = guard;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExternalTransitionConfigurer<S, E> guardExpression(String expression) {
|
||||
SpelExpressionParser parser = new SpelExpressionParser(
|
||||
new SpelParserConfiguration(SpelCompilerMode.MIXED, null));
|
||||
this.guard = new SpelExpressionGuard(parser.parseExpression(expression));
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.expression.spel.SpelCompilerMode;
|
||||
import org.springframework.expression.spel.SpelParserConfiguration;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitions;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerAdapter;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.guard.SpelExpressionGuard;
|
||||
import org.springframework.statemachine.transition.TransitionKind;
|
||||
|
||||
/**
|
||||
* Default implementation of a {@link InternalTransitionConfigurer}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public class DefaultInternalTransitionConfigurer<S, E>
|
||||
extends AnnotationConfigurerAdapter<StateMachineTransitions<S, E>, StateMachineTransitionConfigurer<S, E>, StateMachineTransitionBuilder<S, E>>
|
||||
implements InternalTransitionConfigurer<S, E> {
|
||||
|
||||
private S source;
|
||||
|
||||
private S target;
|
||||
|
||||
private E event;
|
||||
|
||||
private Collection<Action> actions = new ArrayList<Action>();
|
||||
|
||||
private Guard guard;
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineTransitionBuilder<S, E> builder) throws Exception {
|
||||
builder.add(source, target, event, actions, guard, TransitionKind.INTERNAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalTransitionConfigurer<S, E> source(S source) {
|
||||
this.source = source;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalTransitionConfigurer<S, E> event(E event) {
|
||||
this.event = event;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalTransitionConfigurer<S, E> action(Action action) {
|
||||
actions.add(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalTransitionConfigurer<S, E> guard(Guard guard) {
|
||||
this.guard = guard;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InternalTransitionConfigurer<S, E> guardExpression(String expression) {
|
||||
SpelExpressionParser parser = new SpelExpressionParser(
|
||||
new SpelParserConfiguration(SpelCompilerMode.MIXED, null));
|
||||
this.guard = new SpelExpressionGuard(parser.parseExpression(expression));
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateBuilder;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStates.StateData;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerAdapter;
|
||||
|
||||
public class DefaultStateConfigurer<S, E>
|
||||
extends AnnotationConfigurerAdapter<StateMachineStates<S, E>, StateMachineStateConfigurer<S, E>, StateMachineStateBuilder<S, E>>
|
||||
implements StateConfigurer<S, E> {
|
||||
|
||||
private final Collection<StateData<S, E>> states = new ArrayList<StateData<S, E>>();
|
||||
|
||||
private S initial;
|
||||
|
||||
@Override
|
||||
public void configure(StateMachineStateBuilder<S, E> builder) throws Exception {
|
||||
builder.add(states);
|
||||
builder.setInitialState(initial);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> initial(S initial) {
|
||||
this.initial = initial;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> state(S state) {
|
||||
return state(state, (E[])null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> state(S state, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
states.add(new StateData<S, E>(state, null, entryActions, exitActions));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> state(S state, E... deferred) {
|
||||
states.add(new StateData<S, E>(state, deferred));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateConfigurer<S, E> states(Set<S> states) {
|
||||
for (S s : states) {
|
||||
state(s);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
/**
|
||||
* {@code TransitionConfigurer} interface for configuring external {@link Transition}s.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public interface ExternalTransitionConfigurer<S, E> extends
|
||||
TransitionConfigurer<ExternalTransitionConfigurer<S, E>, S, E> {
|
||||
|
||||
/**
|
||||
* Specify a target state {@code S} for this {@link Transition}.
|
||||
*
|
||||
* @param target the target state {@code S}
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
ExternalTransitionConfigurer<S, E> target(S target);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
/**
|
||||
* {@code TransitionConfigurer} interface for configuring internal {@link Transition}s.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public interface InternalTransitionConfigurer<S, E> extends
|
||||
TransitionConfigurer<InternalTransitionConfigurer<S, E>, S, E> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerBuilder;
|
||||
|
||||
public interface StateConfigurer<S, E> extends
|
||||
AnnotationConfigurerBuilder<StateMachineStateConfigurer<S, E>> {
|
||||
|
||||
StateConfigurer<S, E> initial(S initial);
|
||||
|
||||
StateConfigurer<S, E> state(S state);
|
||||
|
||||
StateConfigurer<S, E> state(S state, Collection<Action> entryActions, Collection<Action> exitActions);
|
||||
|
||||
StateConfigurer<S, E> state(S state, E... deferred);
|
||||
|
||||
StateConfigurer<S, E> states(Set<S> states);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.config.configurers;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
|
||||
import org.springframework.statemachine.config.common.annotation.AnnotationConfigurerBuilder;
|
||||
import org.springframework.statemachine.guard.Guard;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
|
||||
/**
|
||||
* Base {@code TransitionConfigurer} interface for configuring {@link Transition}s.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <T> the type of a transition configurer
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public interface TransitionConfigurer<T, S, E> extends
|
||||
AnnotationConfigurerBuilder<StateMachineTransitionConfigurer<S, E>> {
|
||||
|
||||
/**
|
||||
* Specify a source state {@code S} for this {@link Transition}.
|
||||
*
|
||||
* @param source the source state {@code S}
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
T source(S source);
|
||||
|
||||
/**
|
||||
* Specify event {@code E} for this {@link Transition}.
|
||||
*
|
||||
* @param event the event for transition
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
T event(E event);
|
||||
|
||||
/**
|
||||
* Specify {@link Action} for this {@link Transition}.
|
||||
*
|
||||
* @param action the action
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
T action(Action action);
|
||||
|
||||
/**
|
||||
* Specify a {@link Guard} for this {@link Transition}.
|
||||
*
|
||||
* @param guard the guard
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
T guard(Guard guard);
|
||||
|
||||
/**
|
||||
* Specify a {@link Guard} backed by a SpEL expression for this {@link Transition}.
|
||||
*
|
||||
* @param expression the SpEL expression
|
||||
* @return configurer for chaining
|
||||
*/
|
||||
T guardExpression(String expression);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.guard;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
|
||||
/**
|
||||
* {@code Guard}s are typically considered as guard conditions which affect the
|
||||
* behaviour of a state machine by enabling actions or transitions only when they
|
||||
* evaluate to {@code TRUE} and disabling them when they evaluate to
|
||||
* {@code FALSE}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public interface Guard {
|
||||
|
||||
/**
|
||||
* Evaluate a guard condition.
|
||||
*
|
||||
* @param context the state context
|
||||
* @return true, if guard evaluation is successful, false otherwise.
|
||||
*/
|
||||
boolean evaluate(StateContext context);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.guard;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Guard} which uses Spring SpEL expression for condition evaluation.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public class SpelExpressionGuard implements Guard {
|
||||
|
||||
private final Expression expression;
|
||||
|
||||
/**
|
||||
* Instantiates a new spel expression guard.
|
||||
*
|
||||
* @param expression the expression
|
||||
*/
|
||||
public SpelExpressionGuard(Expression expression) {
|
||||
Assert.notNull(expression, "Expression cannot be null");
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(StateContext context) {
|
||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(context);
|
||||
return expression.getValue(evaluationContext, Boolean.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.listener;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Base implementation for all composite listeners.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <T> the type of the listener
|
||||
*/
|
||||
public class AbstractCompositeListener<T> {
|
||||
|
||||
/** List of ordered composite listeners */
|
||||
private OrderedComposite<T> listeners;
|
||||
|
||||
/**
|
||||
* Constructs instance with an empty listener list.
|
||||
*/
|
||||
public AbstractCompositeListener() {
|
||||
listeners = new OrderedComposite<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of listeners. This clears
|
||||
* all existing listeners.
|
||||
*
|
||||
* @param listeners the new listeners
|
||||
*/
|
||||
public void setListeners(List<? extends T> listeners) {
|
||||
this.listeners.setItems(listeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new listener.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public void register(T listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the listeners.
|
||||
*
|
||||
* @return the listeners
|
||||
*/
|
||||
public OrderedComposite<T> getListeners() {
|
||||
return listeners;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.listener;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.statemachine.state.State;
|
||||
|
||||
public class CompositeStateMachineListener<S,E> extends AbstractCompositeListener<StateMachineListener<State<S,E>, E>> implements
|
||||
StateMachineListener<State<S,E>, E> {
|
||||
|
||||
@Override
|
||||
public void stateChanged(State<S, E> from, State<S, E> to) {
|
||||
for (Iterator<StateMachineListener<State<S,E>, E>> iterator = getListeners().reverse(); iterator.hasNext();) {
|
||||
StateMachineListener<State<S,E>, E> listener = iterator.next();
|
||||
listener.stateChanged(from, to);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.listener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
|
||||
/**
|
||||
* Composite item which can be used in other components which
|
||||
* may want to allow automatic and annotation based ordering.
|
||||
* Good use case is a list of listeners where user may want
|
||||
* to place some of them to be processed before the others.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of the item
|
||||
*/
|
||||
public class OrderedComposite<S> {
|
||||
|
||||
private List<S> unordered = new ArrayList<S>();
|
||||
|
||||
private List<S> ordered = new ArrayList<S>();
|
||||
|
||||
private Comparator<? super S> comparator = new AnnotationAwareOrderComparator();
|
||||
|
||||
private List<S> list = new ArrayList<S>();
|
||||
|
||||
/**
|
||||
* Public setter for the listeners.
|
||||
*
|
||||
* @param items items
|
||||
*/
|
||||
public void setItems(List<? extends S> items) {
|
||||
unordered.clear();
|
||||
ordered.clear();
|
||||
for (S s : items) {
|
||||
add(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register additional item.
|
||||
*
|
||||
* @param item item
|
||||
*/
|
||||
public void add(S item) {
|
||||
if (item instanceof Ordered) {
|
||||
if (!ordered.contains(item)) {
|
||||
ordered.add(item);
|
||||
}
|
||||
} else if (AnnotationUtils.isAnnotationDeclaredLocally(Order.class, item.getClass())) {
|
||||
if (!ordered.contains(item)) {
|
||||
ordered.add(item);
|
||||
}
|
||||
} else if (!unordered.contains(item)) {
|
||||
unordered.add(item);
|
||||
}
|
||||
Collections.sort(ordered, comparator);
|
||||
list.clear();
|
||||
list.addAll(ordered);
|
||||
list.addAll(unordered);
|
||||
}
|
||||
|
||||
/**
|
||||
* Public getter for the list of items. The {@link Ordered} items come
|
||||
* first, followed by any unordered ones.
|
||||
*
|
||||
* @return an iterator over the list of items
|
||||
*/
|
||||
public Iterator<S> iterator() {
|
||||
return new ArrayList<S>(list).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Public getter for the list of items in reverse. The {@link Ordered} items
|
||||
* come last, after any unordered ones.
|
||||
*
|
||||
* @return an iterator over the list of items
|
||||
*/
|
||||
public Iterator<S> reverse() {
|
||||
ArrayList<S> result = new ArrayList<S>(list);
|
||||
Collections.reverse(result);
|
||||
return result.iterator();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.listener;
|
||||
|
||||
public interface StateMachineListener<S,E> {
|
||||
|
||||
void stateChanged(S from, S to);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.processor;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Strategy interface for post-processing annotated methods.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <T> the type of an annotation
|
||||
*/
|
||||
public interface MethodAnnotationPostProcessor<T extends Annotation> {
|
||||
|
||||
/**
|
||||
* Post process a bean. As a result of a given bean, its name, method and
|
||||
* annotation in a method, this method can return a new bean or
|
||||
* <code>null</code>. Caller of this method is then responsible to handle
|
||||
* newly created object.
|
||||
*
|
||||
* @param bean the bean
|
||||
* @param beanName the bean name
|
||||
* @param method the method
|
||||
* @param annotation the annotation
|
||||
* @return the object
|
||||
*/
|
||||
Object postProcess(Object bean, String beanName, Method method, T annotation);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.processor;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* A simple {@link StateMachineRuntimeProcessor} implementation using
|
||||
* methods from a state machine protected bean.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <T> the return type
|
||||
*/
|
||||
public class MethodInvokingStateMachineRuntimeProcessor<T> implements StateMachineRuntimeProcessor<T> {
|
||||
|
||||
private final StateMachineMethodInvokerHelper<T> delegate;
|
||||
|
||||
public MethodInvokingStateMachineRuntimeProcessor(Object targetObject, Method method) {
|
||||
delegate = new StateMachineMethodInvokerHelper<T>(targetObject, method);
|
||||
}
|
||||
|
||||
public MethodInvokingStateMachineRuntimeProcessor(Object targetObject, String methodName) {
|
||||
delegate = new StateMachineMethodInvokerHelper<T>(targetObject, methodName);
|
||||
}
|
||||
|
||||
public MethodInvokingStateMachineRuntimeProcessor(Object targetObject, Class<? extends Annotation> annotationType) {
|
||||
delegate = new StateMachineMethodInvokerHelper<T>(targetObject, annotationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T process(StateMachineRuntime stateMachineRuntime) {
|
||||
try {
|
||||
return delegate.process(stateMachineRuntime);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error processing bean", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.processor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.annotation.OrderUtils;
|
||||
import org.springframework.statemachine.annotation.OnTransition;
|
||||
|
||||
/**
|
||||
* Post-processor for Methods annotated with {@link OnTransition}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public class StateMachineActivatorAnnotationPostProcessor implements MethodAnnotationPostProcessor<OnTransition>{
|
||||
|
||||
protected final BeanFactory beanFactory;
|
||||
|
||||
public StateMachineActivatorAnnotationPostProcessor(ListableBeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcess(Object bean, String beanName, Method method, OnTransition annotation) {
|
||||
StateMachineHandler handler = new StateMachineOnTransitionHandler(bean, method, annotation);
|
||||
|
||||
Integer order = findOrder(bean, method);
|
||||
if (order != null) {
|
||||
handler.setOrder(order);
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find {@link Order} order either from a class or
|
||||
* method level. Method level always takes presence
|
||||
* over class level.
|
||||
*
|
||||
* @param bean the bean to inspect
|
||||
* @param method the method to inspect
|
||||
* @return the order or NULL if not found
|
||||
*/
|
||||
private static Integer findOrder(Object bean, Method method) {
|
||||
Integer order = OrderUtils.getOrder(bean.getClass());
|
||||
Order ann = AnnotationUtils.findAnnotation(method, Order.class);
|
||||
if (ann != null) {
|
||||
order = ann.value();
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.processor;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.statemachine.annotation.OnTransition;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* A {@link BeanPostProcessor} implementation that processes method-level
|
||||
* annotations such as {@link OnTransition}.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Marius Bogoevici
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public class StateMachineAnnotationPostProcessor implements BeanPostProcessor, BeanFactoryAware, InitializingBean,
|
||||
Lifecycle, ApplicationListener<ApplicationEvent> {
|
||||
|
||||
private final static Log log = LogFactory.getLog(StateMachineAnnotationPostProcessor.class);
|
||||
|
||||
/** Factory from BeanFactoryAware */
|
||||
private volatile ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
/** Post processors map - annotation -> method post processor */
|
||||
private final Map<Class<? extends Annotation>, MethodAnnotationPostProcessor<?>> postProcessors =
|
||||
new HashMap<Class<? extends Annotation>, MethodAnnotationPostProcessor<?>>();
|
||||
|
||||
/**
|
||||
* Application events for post processed beans (if bean instance of ApplicationListener) will
|
||||
* be dispatched from here via callback in this class.
|
||||
*/
|
||||
private final Set<ApplicationListener<ApplicationEvent>> listeners = new HashSet<ApplicationListener<ApplicationEvent>>();
|
||||
|
||||
/**
|
||||
* Lifecycle callbacks for post processed bean (if bean instance of Lifecycle) will
|
||||
* be dispatched from here via callback in this class.
|
||||
*/
|
||||
private final Set<Lifecycle> lifecycles = new HashSet<Lifecycle>();
|
||||
|
||||
/** Flag for Lifecycle in this class */
|
||||
private volatile boolean running = true;
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
Assert.isAssignable(ConfigurableListableBeanFactory.class, beanFactory.getClass(),
|
||||
"a ConfigurableListableBeanFactory is required");
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
Assert.notNull(beanFactory, "BeanFactory must not be null");
|
||||
postProcessors.put(OnTransition.class, new StateMachineActivatorAnnotationPostProcessor(beanFactory));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
|
||||
Assert.notNull(beanFactory, "BeanFactory must not be null");
|
||||
final Class<?> beanClass = getBeanClass(bean);
|
||||
|
||||
if (!isStereotype(beanClass)) {
|
||||
// we only post-process stereotype components
|
||||
return bean;
|
||||
}
|
||||
|
||||
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
|
||||
|
||||
for (Annotation annotation : annotations) {
|
||||
MethodAnnotationPostProcessor postProcessor = postProcessors.get(annotation.annotationType());
|
||||
|
||||
if (postProcessor != null && shouldCreateHandler(annotation)) {
|
||||
Object result = postProcessor.postProcess(bean, beanName, method, annotation);
|
||||
|
||||
if (result != null && result instanceof StateMachineHandler) {
|
||||
String endpointBeanName = generateBeanName(beanName, method, annotation.annotationType());
|
||||
|
||||
if (result instanceof BeanNameAware) {
|
||||
((BeanNameAware) result).setBeanName(endpointBeanName);
|
||||
}
|
||||
beanFactory.registerSingleton(endpointBeanName, result);
|
||||
if (result instanceof BeanFactoryAware) {
|
||||
((BeanFactoryAware) result).setBeanFactory(beanFactory);
|
||||
}
|
||||
if (result instanceof InitializingBean) {
|
||||
try {
|
||||
((InitializingBean) result).afterPropertiesSet();
|
||||
} catch (Exception e) {
|
||||
throw new BeanInitializationException("failed to initialize annotated component", e);
|
||||
}
|
||||
}
|
||||
if (result instanceof Lifecycle) {
|
||||
lifecycles.add((Lifecycle) result);
|
||||
if (result instanceof SmartLifecycle && ((SmartLifecycle) result).isAutoStartup()) {
|
||||
((SmartLifecycle) result).start();
|
||||
}
|
||||
}
|
||||
if (result instanceof ApplicationListener) {
|
||||
listeners.add((ApplicationListener) result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
for (ApplicationListener<ApplicationEvent> listener : listeners) {
|
||||
try {
|
||||
listener.onApplicationEvent(event);
|
||||
} catch (ClassCastException e) {
|
||||
if (log.isWarnEnabled() && event != null) {
|
||||
log.warn("ApplicationEvent of type [" + event.getClass()
|
||||
+ "] not accepted by ApplicationListener [" + listener + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return this.running;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
for (Lifecycle lifecycle : this.lifecycles) {
|
||||
if (!lifecycle.isRunning()) {
|
||||
lifecycle.start();
|
||||
}
|
||||
}
|
||||
this.running = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
for (Lifecycle lifecycle : this.lifecycles) {
|
||||
if (lifecycle.isRunning()) {
|
||||
lifecycle.stop();
|
||||
}
|
||||
}
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
private boolean shouldCreateHandler(Annotation annotation) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bean class. Will check if bean is a proxy and
|
||||
* find a class from there as target class, otherwise
|
||||
* we just get bean class.
|
||||
*
|
||||
* @param bean the bean
|
||||
* @return the bean class
|
||||
*/
|
||||
private Class<?> getBeanClass(Object bean) {
|
||||
Class<?> targetClass = AopUtils.getTargetClass(bean);
|
||||
return (targetClass != null) ? targetClass : bean.getClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if class is a stereotype meaning if there is
|
||||
* a Component annotation present.
|
||||
*
|
||||
* @param beanClass the bean class
|
||||
* @return true, if is stereotype
|
||||
*/
|
||||
private boolean isStereotype(Class<?> beanClass) {
|
||||
List<Annotation> annotations = new ArrayList<Annotation>(Arrays.asList(beanClass.getAnnotations()));
|
||||
Class<?>[] interfaces = beanClass.getInterfaces();
|
||||
for (Class<?> iface : interfaces) {
|
||||
annotations.addAll(Arrays.asList(iface.getAnnotations()));
|
||||
}
|
||||
for (Annotation annotation : annotations) {
|
||||
Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
if (annotationType.equals(Component.class) || annotationType.isAnnotationPresent(Component.class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String generateBeanName(String originalBeanName, Method method, Class<? extends Annotation> annotationType) {
|
||||
String baseName = originalBeanName + "." + method.getName() + "." + ClassUtils.getShortNameAsProperty(annotationType);
|
||||
String name = baseName;
|
||||
int count = 1;
|
||||
while (beanFactory.containsBean(name)) {
|
||||
name = baseName + "#" + (++count);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.processor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.statemachine.annotation.OnTransition;
|
||||
import org.springframework.statemachine.annotation.WithStateMachine;
|
||||
|
||||
/**
|
||||
* Handler for a common object representing something to be run.
|
||||
* This is usually used when a plain pojo is configured with {@link WithStateMachine}
|
||||
* and {@link OnTransition} annotations.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public class StateMachineHandler implements Ordered {
|
||||
|
||||
private final StateMachineRuntimeProcessor<?> processor;
|
||||
|
||||
private int order = Ordered.LOWEST_PRECEDENCE;
|
||||
|
||||
/**
|
||||
* Instantiates a new container handler.
|
||||
*
|
||||
* @param target the target bean
|
||||
*/
|
||||
// public StateMachineHandler(Object target) {
|
||||
// this(new MethodInvokingStateMachineRuntimeProcessor<Object>(target, OnTransition.class));
|
||||
// }
|
||||
|
||||
/**
|
||||
* Instantiates a new container handler.
|
||||
*
|
||||
* @param target the target bean
|
||||
* @param method the method
|
||||
*/
|
||||
public StateMachineHandler(Object target, Method method) {
|
||||
this(new MethodInvokingStateMachineRuntimeProcessor<Object>(target, method));
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new container handler.
|
||||
*
|
||||
* @param target the target bean
|
||||
* @param methodName the method name
|
||||
*/
|
||||
public StateMachineHandler(Object target, String methodName) {
|
||||
this(new MethodInvokingStateMachineRuntimeProcessor<Object>(target, methodName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new container handler.
|
||||
*
|
||||
* @param <T> the generic type
|
||||
* @param processor the processor
|
||||
*/
|
||||
public <T> StateMachineHandler(MethodInvokingStateMachineRuntimeProcessor<T> processor) {
|
||||
this.processor = processor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the order used get value from {@link #getOrder()}.
|
||||
* Default value is {@link Ordered#LOWEST_PRECEDENCE}.
|
||||
*
|
||||
* @param order the new order
|
||||
*/
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle container using a {@link StateMachineRuntimeProcessor}.
|
||||
*
|
||||
* @param stateMachineRuntime the state machine runtime
|
||||
* @return the result value
|
||||
*/
|
||||
public Object handle(StateMachineRuntime stateMachineRuntime) {
|
||||
return processor.process(stateMachineRuntime);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,553 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.processor;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.TypeConverter;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.support.AbstractExpressionEvaluator;
|
||||
import org.springframework.statemachine.support.AnnotatedMethodFilter;
|
||||
import org.springframework.statemachine.support.FixedMethodFilter;
|
||||
import org.springframework.statemachine.support.UniqueMethodFilter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.MethodCallback;
|
||||
import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||
|
||||
/**
|
||||
* A helper class using spel to execute target methods.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <T> the return type
|
||||
*/
|
||||
public class StateMachineMethodInvokerHelper<T> extends AbstractExpressionEvaluator {
|
||||
|
||||
private static final String CANDIDATE_METHODS = "CANDIDATE_METHODS";
|
||||
|
||||
private static final String CANDIDATE_MESSAGE_METHODS = "CANDIDATE_MESSAGE_METHODS";
|
||||
|
||||
private final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private final Object targetObject;
|
||||
|
||||
private volatile String displayString;
|
||||
|
||||
private volatile boolean requiresReply;
|
||||
|
||||
private final Map<Class<?>, HandlerMethod> handlerMethods;
|
||||
|
||||
private final Map<Class<?>, HandlerMethod> handlerMessageMethods;
|
||||
|
||||
private final LinkedList<Map<Class<?>, HandlerMethod>> handlerMethodsList;
|
||||
|
||||
private final HandlerMethod handlerMethod;
|
||||
|
||||
private final Class<?> expectedType;
|
||||
|
||||
public StateMachineMethodInvokerHelper(Object targetObject, Method method) {
|
||||
this(targetObject, method, null);
|
||||
}
|
||||
|
||||
public StateMachineMethodInvokerHelper(Object targetObject, Method method, Class<?> expectedType) {
|
||||
this(targetObject, null, method, expectedType);
|
||||
}
|
||||
|
||||
public StateMachineMethodInvokerHelper(Object targetObject, String methodName) {
|
||||
this(targetObject, methodName, null);
|
||||
}
|
||||
|
||||
public StateMachineMethodInvokerHelper(Object targetObject, String methodName, Class<?> expectedType) {
|
||||
this(targetObject, null, methodName, expectedType);
|
||||
}
|
||||
|
||||
public StateMachineMethodInvokerHelper(Object targetObject, Class<? extends Annotation> annotationType) {
|
||||
this(targetObject, annotationType, null);
|
||||
}
|
||||
|
||||
public StateMachineMethodInvokerHelper(Object targetObject, Class<? extends Annotation> annotationType,
|
||||
Class<?> expectedType) {
|
||||
this(targetObject, annotationType, (String) null, expectedType);
|
||||
}
|
||||
|
||||
public T process(StateMachineRuntime stateMachineRuntime) throws Exception {
|
||||
ParametersWrapper wrapper = new ParametersWrapper(stateMachineRuntime.getStateContext());
|
||||
return processInternal(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.displayString;
|
||||
}
|
||||
|
||||
private StateMachineMethodInvokerHelper(Object targetObject, Class<? extends Annotation> annotationType,
|
||||
Method method, Class<?> expectedType) {
|
||||
Assert.notNull(method, "method must not be null");
|
||||
this.expectedType = expectedType;
|
||||
this.requiresReply = expectedType != null;
|
||||
if (expectedType != null) {
|
||||
Assert.isTrue(method.getReturnType() != Void.class && method.getReturnType() != Void.TYPE,
|
||||
"method must have a return type");
|
||||
}
|
||||
Assert.notNull(targetObject, "targetObject must not be null");
|
||||
this.targetObject = targetObject;
|
||||
this.handlerMethod = new HandlerMethod(method);
|
||||
this.handlerMethods = null;
|
||||
this.handlerMessageMethods = null;
|
||||
this.handlerMethodsList = null;
|
||||
this.prepareEvaluationContext(this.getEvaluationContext(false), method, annotationType);
|
||||
this.setDisplayString(targetObject, method);
|
||||
}
|
||||
|
||||
private StateMachineMethodInvokerHelper(Object targetObject, Class<? extends Annotation> annotationType,
|
||||
String methodName, Class<?> expectedType) {
|
||||
Assert.notNull(targetObject, "targetObject must not be null");
|
||||
this.expectedType = expectedType;
|
||||
this.targetObject = targetObject;
|
||||
this.requiresReply = expectedType != null;
|
||||
Map<String, Map<Class<?>, HandlerMethod>> handlerMethodsForTarget = this.findHandlerMethodsForTarget(
|
||||
targetObject, annotationType, methodName, requiresReply);
|
||||
Map<Class<?>, HandlerMethod> handlerMethods = handlerMethodsForTarget.get(CANDIDATE_METHODS);
|
||||
Map<Class<?>, HandlerMethod> handlerMessageMethods = handlerMethodsForTarget.get(CANDIDATE_MESSAGE_METHODS);
|
||||
if ((handlerMethods.size() == 1 && handlerMessageMethods.isEmpty())
|
||||
|| (handlerMessageMethods.size() == 1 && handlerMethods.isEmpty())) {
|
||||
if (handlerMethods.size() == 1) {
|
||||
this.handlerMethod = handlerMethods.values().iterator().next();
|
||||
} else {
|
||||
this.handlerMethod = handlerMessageMethods.values().iterator().next();
|
||||
}
|
||||
this.handlerMethods = null;
|
||||
this.handlerMessageMethods = null;
|
||||
this.handlerMethodsList = null;
|
||||
} else {
|
||||
this.handlerMethod = null;
|
||||
this.handlerMethods = handlerMethods;
|
||||
this.handlerMessageMethods = handlerMessageMethods;
|
||||
this.handlerMethodsList = new LinkedList<Map<Class<?>, HandlerMethod>>();
|
||||
|
||||
// TODO Consider to use global option to determine a precedence of
|
||||
// methods
|
||||
this.handlerMethodsList.add(this.handlerMethods);
|
||||
this.handlerMethodsList.add(this.handlerMessageMethods);
|
||||
}
|
||||
this.prepareEvaluationContext(this.getEvaluationContext(false), methodName, annotationType);
|
||||
this.setDisplayString(targetObject, methodName);
|
||||
}
|
||||
|
||||
private void setDisplayString(Object targetObject, Object targetMethod) {
|
||||
StringBuilder sb = new StringBuilder(targetObject.getClass().getName());
|
||||
if (targetMethod instanceof Method) {
|
||||
sb.append("." + ((Method) targetMethod).getName());
|
||||
} else if (targetMethod instanceof String) {
|
||||
sb.append("." + targetMethod);
|
||||
}
|
||||
this.displayString = sb.toString() + "]";
|
||||
}
|
||||
|
||||
private void prepareEvaluationContext(StandardEvaluationContext context, Object method,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
Class<?> targetType = AopUtils.getTargetClass(this.targetObject);
|
||||
if (method instanceof Method) {
|
||||
context.registerMethodFilter(targetType, new FixedMethodFilter((Method) method));
|
||||
if (expectedType != null) {
|
||||
Assert.state(
|
||||
context.getTypeConverter().canConvert(
|
||||
TypeDescriptor.valueOf(((Method) method).getReturnType()),
|
||||
TypeDescriptor.valueOf(expectedType)), "Cannot convert to expected type ("
|
||||
+ expectedType + ") from " + method);
|
||||
}
|
||||
} else if (method == null || method instanceof String) {
|
||||
AnnotatedMethodFilter filter = new AnnotatedMethodFilter(annotationType, (String) method,
|
||||
this.requiresReply);
|
||||
Assert.state(canReturnExpectedType(filter, targetType, context.getTypeConverter()),
|
||||
"Cannot convert to expected type (" + expectedType + ") from " + method);
|
||||
context.registerMethodFilter(targetType, filter);
|
||||
}
|
||||
context.setVariable("target", targetObject);
|
||||
}
|
||||
|
||||
private boolean canReturnExpectedType(AnnotatedMethodFilter filter, Class<?> targetType, TypeConverter typeConverter) {
|
||||
if (expectedType == null) {
|
||||
return true;
|
||||
}
|
||||
List<Method> methods = filter.filter(Arrays.asList(ReflectionUtils.getAllDeclaredMethods(targetType)));
|
||||
for (Method method : methods) {
|
||||
if (typeConverter.canConvert(TypeDescriptor.valueOf(method.getReturnType()), TypeDescriptor.valueOf(expectedType))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private T processInternal(ParametersWrapper parameters) throws Exception {
|
||||
HandlerMethod candidate = this.findHandlerMethodForParameters(parameters);
|
||||
Assert.notNull(candidate, "No candidate methods found for messages.");
|
||||
Expression expression = candidate.getExpression();
|
||||
Class<?> expectedType = this.expectedType != null ? this.expectedType : candidate.method.getReturnType();
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
T result = (T) this.evaluateExpression(expression, parameters, expectedType);
|
||||
if (this.requiresReply) {
|
||||
Assert.notNull(result, "Expression evaluation result was null, but this processor requires a reply.");
|
||||
}
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
Throwable evaluationException = e;
|
||||
if (e instanceof EvaluationException && e.getCause() != null) {
|
||||
evaluationException = e.getCause();
|
||||
}
|
||||
if (evaluationException instanceof Exception) {
|
||||
throw (Exception) evaluationException;
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot process message", evaluationException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Map<Class<?>, HandlerMethod>> findHandlerMethodsForTarget(final Object targetObject,
|
||||
final Class<? extends Annotation> annotationType, final String methodName, final boolean requiresReply) {
|
||||
|
||||
Map<String, Map<Class<?>, HandlerMethod>> handlerMethods = new HashMap<String, Map<Class<?>, HandlerMethod>>();
|
||||
|
||||
final Map<Class<?>, HandlerMethod> candidateMethods = new HashMap<Class<?>, HandlerMethod>();
|
||||
final Map<Class<?>, HandlerMethod> candidateMessageMethods = new HashMap<Class<?>, HandlerMethod>();
|
||||
final Class<?> targetClass = this.getTargetClass(targetObject);
|
||||
MethodFilter methodFilter = new UniqueMethodFilter(targetClass);
|
||||
ReflectionUtils.doWithMethods(targetClass, new MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
boolean matchesAnnotation = false;
|
||||
if (method.isBridge()) {
|
||||
return;
|
||||
}
|
||||
if (isMethodDefinedOnObjectClass(method)) {
|
||||
return;
|
||||
}
|
||||
if (method.getDeclaringClass().equals(Proxy.class)) {
|
||||
return;
|
||||
}
|
||||
if (!Modifier.isPublic(method.getModifiers())) {
|
||||
return;
|
||||
}
|
||||
if (requiresReply && void.class.equals(method.getReturnType())) {
|
||||
return;
|
||||
}
|
||||
if (methodName != null && !methodName.equals(method.getName())) {
|
||||
return;
|
||||
}
|
||||
if (annotationType != null && AnnotationUtils.findAnnotation(method, annotationType) != null) {
|
||||
matchesAnnotation = true;
|
||||
}
|
||||
HandlerMethod handlerMethod = null;
|
||||
try {
|
||||
handlerMethod = new HandlerMethod(method);
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Method [" + method + "] is not eligible for container handling.", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Class<?> targetParameterType = handlerMethod.getTargetParameterType();
|
||||
if (matchesAnnotation || annotationType == null) {
|
||||
if (handlerMethod.isMessageMethod()) {
|
||||
if (candidateMessageMethods.containsKey(targetParameterType)) {
|
||||
throw new IllegalArgumentException("Found more than one method match for type " +
|
||||
"[Message<" + targetParameterType + ">]");
|
||||
}
|
||||
candidateMessageMethods.put(targetParameterType, handlerMethod);
|
||||
} else {
|
||||
if (candidateMethods.containsKey(targetParameterType)) {
|
||||
String exceptionMessage = "Found more than one method match for ";
|
||||
if (Void.class.equals(targetParameterType)) {
|
||||
exceptionMessage += "empty parameter for 'payload'";
|
||||
} else {
|
||||
exceptionMessage += "type [" + targetParameterType + "]";
|
||||
}
|
||||
throw new IllegalArgumentException(exceptionMessage);
|
||||
}
|
||||
candidateMethods.put(targetParameterType, handlerMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, methodFilter);
|
||||
|
||||
if (!candidateMethods.isEmpty() || !candidateMessageMethods.isEmpty()) {
|
||||
handlerMethods.put(CANDIDATE_METHODS, candidateMethods);
|
||||
handlerMethods.put(CANDIDATE_MESSAGE_METHODS, candidateMessageMethods);
|
||||
return handlerMethods;
|
||||
}
|
||||
|
||||
Assert.state(!handlerMethods.isEmpty(), "Target object of type [" + this.targetObject.getClass()
|
||||
+ "] has no eligible methods for handling Container.");
|
||||
|
||||
return handlerMethods;
|
||||
}
|
||||
|
||||
private Class<?> getTargetClass(Object targetObject) {
|
||||
Class<?> targetClass = targetObject.getClass();
|
||||
if (AopUtils.isAopProxy(targetObject)) {
|
||||
targetClass = AopUtils.getTargetClass(targetObject);
|
||||
if (targetClass == targetObject.getClass()) {
|
||||
try {
|
||||
// Maybe a proxy with no target - e.g. gateway
|
||||
Class<?>[] interfaces = ((Advised) targetObject).getProxiedInterfaces();
|
||||
if (interfaces != null && interfaces.length == 1) {
|
||||
targetClass = interfaces[0];
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Exception trying to extract interface", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (org.springframework.util.ClassUtils.isCglibProxyClass(targetClass)) {
|
||||
Class<?> superClass = targetObject.getClass().getSuperclass();
|
||||
if (!Object.class.equals(superClass)) {
|
||||
targetClass = superClass;
|
||||
}
|
||||
}
|
||||
return targetClass;
|
||||
}
|
||||
|
||||
private HandlerMethod findHandlerMethodForParameters(ParametersWrapper parameters) {
|
||||
if (this.handlerMethod != null) {
|
||||
return this.handlerMethod;
|
||||
} else {
|
||||
return this.handlerMethods.get(Void.class);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isMethodDefinedOnObjectClass(Method method) {
|
||||
if (method == null) {
|
||||
return false;
|
||||
}
|
||||
if (method.getDeclaringClass().equals(Object.class)) {
|
||||
return true;
|
||||
}
|
||||
if (ReflectionUtils.isEqualsMethod(method) || ReflectionUtils.isHashCodeMethod(method)
|
||||
|| ReflectionUtils.isToStringMethod(method) || AopUtils.isFinalizeMethod(method)) {
|
||||
return true;
|
||||
}
|
||||
return (method.getName().equals("clone") && method.getParameterTypes().length == 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper class for generating and exposing metadata for a candidate handler method. The metadata includes the SpEL
|
||||
* expression and the expected payload type.
|
||||
*/
|
||||
private static class HandlerMethod {
|
||||
|
||||
private static final SpelExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
|
||||
|
||||
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new LocalVariableTableParameterNameDiscoverer();
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Expression expression;
|
||||
|
||||
private volatile TypeDescriptor targetParameterTypeDescriptor;
|
||||
|
||||
private volatile Class<?> targetParameterType = Void.class;
|
||||
|
||||
private volatile boolean messageMethod;
|
||||
|
||||
HandlerMethod(Method method) {
|
||||
this.method = method;
|
||||
this.expression = this.generateExpression(method);
|
||||
}
|
||||
|
||||
|
||||
Expression getExpression() {
|
||||
return this.expression;
|
||||
}
|
||||
|
||||
Class<?> getTargetParameterType() {
|
||||
return this.targetParameterType;
|
||||
}
|
||||
|
||||
private boolean isMessageMethod() {
|
||||
return messageMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.method.toString();
|
||||
}
|
||||
|
||||
private Expression generateExpression(Method method) {
|
||||
StringBuilder sb = new StringBuilder("#target." + method.getName() + "(");
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
|
||||
boolean hasUnqualifiedMapParameter = false;
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
if (i != 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
MethodParameter methodParameter = new MethodParameter(method, i);
|
||||
TypeDescriptor parameterTypeDescriptor = new TypeDescriptor(methodParameter);
|
||||
Class<?> parameterType = parameterTypeDescriptor.getObjectType();
|
||||
Annotation mappingAnnotation = findMappingAnnotation(parameterAnnotations[i]);
|
||||
if (mappingAnnotation != null) {
|
||||
Class<? extends Annotation> annotationType = mappingAnnotation.annotationType();
|
||||
|
||||
// if (annotationType.equals(YarnEnvironments.class)) {
|
||||
// sb.append("environment");
|
||||
// } else if (annotationType.equals(YarnEnvironment.class)) {
|
||||
// YarnEnvironment headerAnnotation = (YarnEnvironment) mappingAnnotation;
|
||||
// sb.append(this.determineEnvironmentExpression(headerAnnotation, methodParameter));
|
||||
// } else if (annotationType.equals(YarnParameters.class)) {
|
||||
// Assert.isTrue(Map.class.isAssignableFrom(parameterType),
|
||||
// "The @YarnParameters annotation can only be applied to a Map-typed parameter.");
|
||||
// sb.append("parameters");
|
||||
// } else if (annotationType.equals(YarnParameter.class)) {
|
||||
// YarnParameter headerAnnotation = (YarnParameter) mappingAnnotation;
|
||||
// sb.append(this.determineParameterExpression(headerAnnotation, methodParameter));
|
||||
// }
|
||||
}
|
||||
}
|
||||
if (hasUnqualifiedMapParameter) {
|
||||
if (targetParameterType != null && Map.class.isAssignableFrom(this.targetParameterType)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to determine payload matching parameter due to ambiguous Map typed parameters. "
|
||||
+ "Consider adding the @Payload and or @Headers annotations as appropriate.");
|
||||
}
|
||||
}
|
||||
sb.append(")");
|
||||
if (this.targetParameterTypeDescriptor == null) {
|
||||
this.targetParameterTypeDescriptor = TypeDescriptor.valueOf(Void.class);
|
||||
}
|
||||
return EXPRESSION_PARSER.parseExpression(sb.toString());
|
||||
}
|
||||
|
||||
private Annotation findMappingAnnotation(Annotation[] annotations) {
|
||||
if (annotations == null || annotations.length == 0) {
|
||||
return null;
|
||||
}
|
||||
Annotation match = null;
|
||||
for (Annotation annotation : annotations) {
|
||||
Class<? extends Annotation> type = annotation.annotationType();
|
||||
// if (type.equals(YarnParameters.class) || type.equals(YarnParameter.class)
|
||||
// || type.equals(YarnEnvironments.class) || type.equals(YarnEnvironment.class)) {
|
||||
// if (match != null) {
|
||||
// throw new IllegalArgumentException(
|
||||
// "At most one parameter annotation can be provided for message mapping, "
|
||||
// + "but found two: [" + match.annotationType().getName() + "] and ["
|
||||
// + annotation.annotationType().getName() + "]");
|
||||
// }
|
||||
// match = annotation;
|
||||
// }
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
// private String determineParameterExpression(YarnParameter parameterAnnotation, MethodParameter methodParameter) {
|
||||
// methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);
|
||||
// String headerName = null;
|
||||
// String relativeExpression = "";
|
||||
// String valueAttribute = parameterAnnotation.value();
|
||||
// if (!StringUtils.hasText(valueAttribute)) {
|
||||
// headerName = methodParameter.getParameterName();
|
||||
// } else if (valueAttribute.indexOf('.') != -1) {
|
||||
// String tokens[] = valueAttribute.split("\\.", 2);
|
||||
// headerName = tokens[0];
|
||||
// if (StringUtils.hasText(tokens[1])) {
|
||||
// relativeExpression = "." + tokens[1];
|
||||
// }
|
||||
// } else {
|
||||
// headerName = valueAttribute;
|
||||
// }
|
||||
// Assert.notNull(headerName, "Cannot determine parameter name. Possible reasons: -debug is "
|
||||
// + "disabled or header name is not explicitly provided via @YarnParameter annotation.");
|
||||
// String headerRetrievalExpression = "parameters['" + headerName + "']";
|
||||
// String fullHeaderExpression = headerRetrievalExpression + relativeExpression;
|
||||
// String fallbackExpression = (parameterAnnotation.required()) ? "T(org.springframework.util.Assert).isTrue(false, 'required parameter not available: "
|
||||
// + headerName + "')"
|
||||
// : "null";
|
||||
// return headerRetrievalExpression + " != null ? " + fullHeaderExpression + " : " + fallbackExpression;
|
||||
// }
|
||||
|
||||
// private String determineEnvironmentExpression(YarnEnvironment environmentAnnotation, MethodParameter methodParameter) {
|
||||
// methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);
|
||||
// String headerName = null;
|
||||
// String relativeExpression = "";
|
||||
// String valueAttribute = environmentAnnotation.value();
|
||||
// if (!StringUtils.hasText(valueAttribute)) {
|
||||
// headerName = methodParameter.getParameterName();
|
||||
// } else if (valueAttribute.indexOf('.') != -1) {
|
||||
// String tokens[] = valueAttribute.split("\\.", 2);
|
||||
// headerName = tokens[0];
|
||||
// if (StringUtils.hasText(tokens[1])) {
|
||||
// relativeExpression = "." + tokens[1];
|
||||
// }
|
||||
// } else {
|
||||
// headerName = valueAttribute;
|
||||
// }
|
||||
// Assert.notNull(headerName, "Cannot determine parameter name. Possible reasons: -debug is "
|
||||
// + "disabled or header name is not explicitly provided via @YarnEnvironment annotation.");
|
||||
// String headerRetrievalExpression = "environment['" + headerName + "']";
|
||||
// String fullHeaderExpression = headerRetrievalExpression + relativeExpression;
|
||||
// String fallbackExpression = (environmentAnnotation.required()) ? "T(org.springframework.util.Assert).isTrue(false, 'required parameter not available: "
|
||||
// + headerName + "')"
|
||||
// : "null";
|
||||
// return headerRetrievalExpression + " != null ? " + fullHeaderExpression + " : " + fallbackExpression;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapping everything we need to work with spel.
|
||||
*/
|
||||
public class ParametersWrapper {
|
||||
|
||||
private final StateContext stateContext;
|
||||
|
||||
public ParametersWrapper(StateContext stateContext) {
|
||||
this.stateContext = stateContext;
|
||||
}
|
||||
|
||||
public StateContext getStateContext() {
|
||||
return stateContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.processor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.statemachine.annotation.OnTransition;
|
||||
|
||||
public class StateMachineOnTransitionHandler extends StateMachineHandler {
|
||||
|
||||
private OnTransition annotation;
|
||||
|
||||
public StateMachineOnTransitionHandler(Object target, Method method, OnTransition annotation) {
|
||||
super(target, method);
|
||||
this.annotation = annotation;
|
||||
}
|
||||
|
||||
public OnTransition getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.processor;
|
||||
|
||||
import org.springframework.statemachine.StateContext;
|
||||
|
||||
/**
|
||||
* A generic runtime representation of a state machine.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public interface StateMachineRuntime {
|
||||
|
||||
StateContext getStateContext();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.processor;
|
||||
|
||||
/**
|
||||
* Defines a strategy of processing a state machine and returning
|
||||
* some Object (or null).
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <T> type
|
||||
*/
|
||||
public interface StateMachineRuntimeProcessor<T> {
|
||||
|
||||
/**
|
||||
* Process the container based on information available
|
||||
* from {@link StateMachineRuntime}.
|
||||
*
|
||||
* @param stateMachineRuntime the yarn container runtime
|
||||
* @return the result
|
||||
*/
|
||||
T process(StateMachineRuntime stateMachineRuntime);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.state;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
|
||||
public abstract class AbstractState<S, E> implements State<S, E> {
|
||||
|
||||
private S id;
|
||||
private Collection<E> deferred;
|
||||
private Collection<Action> entryActions;
|
||||
private Collection<Action> exitActions;
|
||||
|
||||
public AbstractState(S id) {
|
||||
this(id, null);
|
||||
}
|
||||
|
||||
public AbstractState(S id, Collection<E> deferred) {
|
||||
this(id, deferred, null, null);
|
||||
}
|
||||
|
||||
public AbstractState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
this.id = id;
|
||||
this.deferred = deferred;
|
||||
this.entryActions = entryActions;
|
||||
this.exitActions = exitActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public S getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<E> getDeferredEvents() {
|
||||
return deferred;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Action> getEntryActions() {
|
||||
return entryActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Action> getExitActions() {
|
||||
return exitActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AbstractState [id=" + id + ", deferred=" + deferred + ", entryActions=" + entryActions
|
||||
+ ", exitActions=" + exitActions + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.state;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
|
||||
public class EnumState<S extends Enum<S>, E extends Enum<E>> extends AbstractState<S, E> {
|
||||
|
||||
public EnumState(S id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
public EnumState(S id, Collection<E> deferred) {
|
||||
super(id, deferred);
|
||||
}
|
||||
|
||||
public EnumState(S id, Collection<E> deferred, Collection<Action> entryActions, Collection<Action> exitActions) {
|
||||
super(id, deferred, entryActions, exitActions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EnumState [getId()=" + getId() + ", getClass()=" + getClass() + ", hashCode()=" + hashCode()
|
||||
+ ", toString()=" + super.toString() + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.state;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.statemachine.action.Action;
|
||||
|
||||
/**
|
||||
* {@code State} is an interface representing possible state in a state machine.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public interface State<S, E> {
|
||||
|
||||
/**
|
||||
* Gets the state identifier.
|
||||
*
|
||||
* @return the identifier
|
||||
*/
|
||||
S getId();
|
||||
|
||||
/**
|
||||
* Gets the deferred events for this state.
|
||||
*
|
||||
* @return the state deferred events
|
||||
*/
|
||||
Collection<E> getDeferredEvents();
|
||||
|
||||
/**
|
||||
* Gets {@link Action}s executed entering in this state.
|
||||
*
|
||||
* @return the state entry actions
|
||||
*/
|
||||
Collection<Action> getEntryActions();
|
||||
|
||||
/**
|
||||
* Gets {@link Action}s executed exiting from this state.
|
||||
*
|
||||
* @return the state exit actions
|
||||
*/
|
||||
Collection<Action> getExitActions();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
/**
|
||||
* Base class providing common functionality for using Spring expression language.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Dave Syer
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractExpressionEvaluator implements BeanFactoryAware, InitializingBean {
|
||||
|
||||
private volatile StandardEvaluationContext evaluationContext;
|
||||
|
||||
private final ExpressionParser expressionParser = new SpelExpressionParser();
|
||||
|
||||
private final BeanFactoryTypeConverter typeConverter = new BeanFactoryTypeConverter();
|
||||
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(final BeanFactory beanFactory) {
|
||||
if (beanFactory != null) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.typeConverter.setBeanFactory(beanFactory);
|
||||
if (this.evaluationContext != null && this.evaluationContext.getBeanResolver() == null) {
|
||||
this.evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
getEvaluationContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the conversion service.
|
||||
*
|
||||
* @param conversionService the new conversion service
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
if (conversionService != null) {
|
||||
this.typeConverter.setConversionService(conversionService);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the evaluation context.
|
||||
*
|
||||
* @return the evaluation context
|
||||
*/
|
||||
protected StandardEvaluationContext getEvaluationContext() {
|
||||
return this.getEvaluationContext(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a WARN log if the beanFactory field is null, unless the argument is false.
|
||||
* @param beanFactoryRequired set to false to suppress the warning.
|
||||
* @return The evaluation context.
|
||||
*/
|
||||
protected final StandardEvaluationContext getEvaluationContext(boolean beanFactoryRequired) {
|
||||
if (this.evaluationContext == null) {
|
||||
if (this.beanFactory == null && !beanFactoryRequired) {
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext();
|
||||
}
|
||||
else {
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.beanFactory);
|
||||
}
|
||||
if (this.typeConverter != null) {
|
||||
this.evaluationContext.setTypeConverter(this.typeConverter);
|
||||
}
|
||||
}
|
||||
return this.evaluationContext;
|
||||
}
|
||||
|
||||
protected Object evaluateExpression(String expression, Object input) {
|
||||
return this.evaluateExpression(expression, input, (Class<?>) null);
|
||||
}
|
||||
|
||||
protected <T> T evaluateExpression(String expression, Object input, Class<T> expectedType) {
|
||||
return this.expressionParser.parseExpression(expression).getValue(this.getEvaluationContext(), input, expectedType);
|
||||
}
|
||||
|
||||
protected Object evaluateExpression(Expression expression, Object input) {
|
||||
return this.evaluateExpression(expression, input, (Class<?>) null);
|
||||
}
|
||||
|
||||
protected <T> T evaluateExpression(Expression expression, Class<T> expectedType) {
|
||||
return expression.getValue(this.getEvaluationContext(), expectedType);
|
||||
}
|
||||
|
||||
protected Object evaluateExpression(Expression expression) {
|
||||
return expression.getValue(this.getEvaluationContext());
|
||||
}
|
||||
|
||||
protected <T> T evaluateExpression(Expression expression, Object input, Class<T> expectedType) {
|
||||
return expression.getValue(this.getEvaluationContext(), input, expectedType);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.statemachine.ExtendedState;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
import org.springframework.statemachine.StateMachine;
|
||||
import org.springframework.statemachine.action.Action;
|
||||
import org.springframework.statemachine.annotation.OnTransition;
|
||||
import org.springframework.statemachine.listener.CompositeStateMachineListener;
|
||||
import org.springframework.statemachine.listener.StateMachineListener;
|
||||
import org.springframework.statemachine.processor.StateMachineHandler;
|
||||
import org.springframework.statemachine.processor.StateMachineOnTransitionHandler;
|
||||
import org.springframework.statemachine.processor.StateMachineRuntime;
|
||||
import org.springframework.statemachine.state.State;
|
||||
import org.springframework.statemachine.transition.Transition;
|
||||
import org.springframework.statemachine.transition.TransitionKind;
|
||||
import org.springframework.statemachine.trigger.Trigger;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base implementation of a {@link StateMachine} loosely modelled from UML state
|
||||
* machine.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
* @param <S> the type of state
|
||||
* @param <E> the type of event
|
||||
*/
|
||||
public abstract class AbstractStateMachine<S, E> extends LifecycleObjectSupport implements StateMachine<State<S,E>, E> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(AbstractStateMachine.class);
|
||||
|
||||
private final Collection<State<S,E>> states;
|
||||
|
||||
private final Collection<Transition<S,E>> transitions;
|
||||
|
||||
private final State<S,E> initialState;
|
||||
|
||||
private final ExtendedState extendedState;
|
||||
|
||||
private final Queue<Message<E>> eventQueue = new ConcurrentLinkedQueue<Message<E>>();
|
||||
|
||||
private final LinkedList<Message<E>> deferList = new LinkedList<Message<E>>();
|
||||
|
||||
private final CompositeStateMachineListener<S, E> stateListener = new CompositeStateMachineListener<S, E>();
|
||||
|
||||
private volatile State<S,E> currentState;
|
||||
|
||||
private volatile Runnable task;
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state machine.
|
||||
*
|
||||
* @param states the states of this machine
|
||||
* @param transitions the transitions of this machine
|
||||
* @param initialState the initial state of this machine
|
||||
*/
|
||||
public AbstractStateMachine(Collection<State<S, E>> states, Collection<Transition<S, E>> transitions,
|
||||
State<S, E> initialState) {
|
||||
this(states, transitions, initialState, new DefaultExtendedState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new abstract state machine.
|
||||
*
|
||||
* @param states the states of this machine
|
||||
* @param transitions the transitions of this machine
|
||||
* @param initialState the initial state of this machine
|
||||
* @param extendedState the extended state of this machine
|
||||
*/
|
||||
public AbstractStateMachine(Collection<State<S, E>> states, Collection<Transition<S, E>> transitions,
|
||||
State<S, E> initialState, ExtendedState extendedState) {
|
||||
super();
|
||||
this.states = states;
|
||||
this.transitions = transitions;
|
||||
this.initialState = initialState;
|
||||
this.extendedState = extendedState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State<S,E> getState() {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State<S,E> getInitialState() {
|
||||
return initialState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEvent(Message<E> event) {
|
||||
// TODO: machine header looks weird!
|
||||
event = MessageBuilder.fromMessage(event).setHeader("machine", this).build();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Queue event " + event);
|
||||
}
|
||||
eventQueue.add(event);
|
||||
scheduleEventQueueProcessing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendEvent(E event) {
|
||||
sendEvent(MessageBuilder.withPayload(event).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() {
|
||||
super.doStart();
|
||||
switchToState(initialState, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addStateListener(StateMachineListener<State<S, E>, E> listener) {
|
||||
stateListener.register(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link State}s defined in this machine. Returned collection is
|
||||
* an unmodifiable copy because states in a state machine are immutable.
|
||||
*
|
||||
* @return immutable copy of existing states
|
||||
*/
|
||||
public Collection<State<S,E>> getStates() {
|
||||
return Collections.unmodifiableCollection(states);
|
||||
}
|
||||
|
||||
private void switchToState(State<S,E> state, Message<E> event) {
|
||||
log.info("Moving into state=" + state + " from " + currentState);
|
||||
|
||||
exitFromState(currentState, event);
|
||||
stateListener.stateChanged(currentState, state);
|
||||
|
||||
callHandlers(currentState, state, event);
|
||||
|
||||
currentState = state;
|
||||
entryToState(state, event);
|
||||
|
||||
for (Transition<S,E> transition : transitions) {
|
||||
State<S,E> source = transition.getSource();
|
||||
State<S,E> target = transition.getTarget();
|
||||
if (transition.getTrigger() == null && source.equals(currentState)) {
|
||||
switchToState(target, event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void exitFromState(State<S, E> state, Message<E> event) {
|
||||
if (state != null) {
|
||||
MessageHeaders messageHeaders = event != null ? event.getHeaders() : new MessageHeaders(
|
||||
new HashMap<String, Object>());
|
||||
Collection<Action> actions = state.getExitActions();
|
||||
if (actions != null) {
|
||||
for (Action action : actions) {
|
||||
action.execute(new DefaultStateContext(messageHeaders, extendedState));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void entryToState(State<S,E> state, Message<E> event) {
|
||||
if (state != null) {
|
||||
MessageHeaders messageHeaders = event != null ? event.getHeaders() : new MessageHeaders(
|
||||
new HashMap<String, Object>());
|
||||
Collection<Action> actions = state.getEntryActions();
|
||||
if (actions != null) {
|
||||
for (Action action : actions) {
|
||||
action.execute(new DefaultStateContext(messageHeaders, extendedState));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processEventQueue() {
|
||||
log.debug("Process event queue");
|
||||
Message<E> queuedEvent = null;
|
||||
while ((queuedEvent = eventQueue.poll()) != null) {
|
||||
Message<E> defer = null;
|
||||
for (Transition<S,E> transition : transitions) {
|
||||
State<S,E> source = transition.getSource();
|
||||
State<S,E> target = transition.getTarget();
|
||||
Trigger<S, E> trigger = transition.getTrigger();
|
||||
if (source.equals(currentState)) {
|
||||
if (trigger != null && trigger.evaluate(queuedEvent.getPayload())) {
|
||||
boolean transit = transition.transit(new DefaultStateContext(queuedEvent.getHeaders(), extendedState));
|
||||
if (transit && transition.getKind() != TransitionKind.INTERNAL) {
|
||||
switchToState(target, queuedEvent);
|
||||
}
|
||||
break;
|
||||
} else if (source.getDeferredEvents() != null && source.getDeferredEvents().contains(queuedEvent.getPayload())) {
|
||||
defer = queuedEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (defer != null) {
|
||||
log.info("Deferring event " + defer);
|
||||
deferList.addLast(defer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processDeferList() {
|
||||
log.debug("Process defer list");
|
||||
ListIterator<Message<E>> iterator = deferList.listIterator();
|
||||
while (iterator.hasNext()) {
|
||||
Message<E> event = iterator.next();
|
||||
for (Transition<S,E> transition : transitions) {
|
||||
State<S,E> source = transition.getSource();
|
||||
State<S,E> target = transition.getTarget();
|
||||
Trigger<S, E> trigger = transition.getTrigger();
|
||||
if (source.equals(currentState)) {
|
||||
if (trigger != null && trigger.evaluate(event.getPayload())) {
|
||||
boolean transit = transition.transit(new DefaultStateContext(event.getHeaders(), extendedState));
|
||||
if (transit && transition.getKind() != TransitionKind.INTERNAL) {
|
||||
switchToState(target, event);
|
||||
}
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleEventQueueProcessing() {
|
||||
if (task == null) {
|
||||
task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
processEventQueue();
|
||||
processDeferList();
|
||||
task = null;
|
||||
}
|
||||
};
|
||||
getTaskExecutor().execute(task);
|
||||
}
|
||||
}
|
||||
|
||||
private void callHandlers(State<S,E> sourceState, State<S,E> targetState, Message<E> event) {
|
||||
if (sourceState != null && targetState != null) {
|
||||
MessageHeaders messageHeaders = event != null ? event.getHeaders() : new MessageHeaders(
|
||||
new HashMap<String, Object>());
|
||||
StateContext stateContext = new DefaultStateContext(messageHeaders, extendedState);
|
||||
getStateMachineHandlerResults(getStateMachineHandlers(sourceState, targetState), stateContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private List<Object> getStateMachineHandlerResults(List<StateMachineHandler> stateMachineHandlers, final StateContext stateContext) {
|
||||
StateMachineRuntime runtime = new StateMachineRuntime() {
|
||||
@Override
|
||||
public StateContext getStateContext() {
|
||||
return stateContext;
|
||||
}
|
||||
};
|
||||
List<Object> results = new ArrayList<Object>();
|
||||
for (StateMachineHandler handler : stateMachineHandlers) {
|
||||
results.add(handler.handle(runtime));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<StateMachineHandler> getStateMachineHandlers(State<S,E> sourceState, State<S,E> targetState) {
|
||||
BeanFactory beanFactory = getBeanFactory();
|
||||
|
||||
// TODO think how to handle null bf
|
||||
if (beanFactory == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Assert.state(beanFactory instanceof ListableBeanFactory, "Bean factory must be instance of ListableBeanFactory");
|
||||
Map<String, StateMachineOnTransitionHandler> handlers = ((ListableBeanFactory) beanFactory)
|
||||
.getBeansOfType(StateMachineOnTransitionHandler.class);
|
||||
List<StateMachineHandler> handlersList = new ArrayList<StateMachineHandler>();
|
||||
|
||||
for (Entry<String, StateMachineOnTransitionHandler> entry : handlers.entrySet()) {
|
||||
OnTransition annotation = entry.getValue().getAnnotation();
|
||||
String source = annotation.source();
|
||||
String target = annotation.target();
|
||||
String s = sourceState.getId().toString();
|
||||
String t = targetState.getId().toString();
|
||||
if (s.equals(source) && t.equals(target)) {
|
||||
handlersList.add(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
OrderComparator comparator = new OrderComparator();
|
||||
Collections.sort(handlersList, comparator);
|
||||
return handlersList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.expression.MethodFilter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A MethodFilter implementation that enables the following:
|
||||
* <ol>
|
||||
* <li>matching on method name, if available</li>
|
||||
* <li>exclusion of void-returning methods if 'requiresReply' is true</li>
|
||||
* <li>limiting to annotated methods if at least one is present</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Janne Valkealahti
|
||||
*/
|
||||
public class AnnotatedMethodFilter implements MethodFilter {
|
||||
|
||||
private final Class<? extends Annotation> annotationType;
|
||||
|
||||
private final String methodName;
|
||||
|
||||
private final boolean requiresReply;
|
||||
|
||||
public AnnotatedMethodFilter(Class<? extends Annotation> annotationType, String methodName, boolean requiresReply) {
|
||||
this.annotationType = annotationType;
|
||||
this.methodName = methodName;
|
||||
this.requiresReply = requiresReply;
|
||||
}
|
||||
|
||||
public List<Method> filter(List<Method> methods) {
|
||||
List<Method> annotatedCandidates = new ArrayList<Method>();
|
||||
List<Method> fallbackCandidates = new ArrayList<Method>();
|
||||
for (Method method : methods) {
|
||||
if (method.isBridge()) {
|
||||
continue;
|
||||
}
|
||||
if (this.requiresReply && method.getReturnType().equals(void.class)) {
|
||||
continue;
|
||||
}
|
||||
if (StringUtils.hasText(this.methodName) && !this.methodName.equals(method.getName())) {
|
||||
continue;
|
||||
}
|
||||
if (this.annotationType != null && AnnotationUtils.findAnnotation(method, this.annotationType) != null) {
|
||||
annotatedCandidates.add(method);
|
||||
} else {
|
||||
fallbackCandidates.add(method);
|
||||
}
|
||||
}
|
||||
return (!annotatedCandidates.isEmpty()) ? annotatedCandidates : fallbackCandidates;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import java.beans.PropertyEditor;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.SimpleTypeConverter;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.expression.TypeConverter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
* @author Soby Chacko
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public class BeanFactoryTypeConverter implements TypeConverter, BeanFactoryAware {
|
||||
|
||||
private static ConversionService defaultConversionService;
|
||||
|
||||
private volatile SimpleTypeConverter delegate = new SimpleTypeConverter();
|
||||
|
||||
private volatile boolean haveCalledDelegateGetDefaultEditor;
|
||||
|
||||
private volatile ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* Instantiates a new bean factory type converter.
|
||||
*/
|
||||
public BeanFactoryTypeConverter() {
|
||||
synchronized (BeanFactoryTypeConverter.class) {
|
||||
if (defaultConversionService == null) {
|
||||
defaultConversionService = new DefaultConversionService();
|
||||
}
|
||||
}
|
||||
this.conversionService = defaultConversionService;
|
||||
}
|
||||
|
||||
public BeanFactoryTypeConverter(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
if (beanFactory instanceof ConfigurableBeanFactory) {
|
||||
Object typeConverter = ((ConfigurableBeanFactory) beanFactory).getTypeConverter();
|
||||
if (typeConverter instanceof SimpleTypeConverter) {
|
||||
delegate = (SimpleTypeConverter) typeConverter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
|
||||
if (conversionService.canConvert(sourceType, targetType)) {
|
||||
return true;
|
||||
}
|
||||
if (!String.class.isAssignableFrom(sourceType) && !String.class.isAssignableFrom(targetType)) {
|
||||
// PropertyEditor cannot convert non-Strings
|
||||
return false;
|
||||
}
|
||||
if (!String.class.isAssignableFrom(sourceType)) {
|
||||
return delegate.findCustomEditor(sourceType, null) != null || this.getDefaultEditor(sourceType) != null;
|
||||
}
|
||||
return delegate.findCustomEditor(targetType, null) != null || this.getDefaultEditor(targetType) != null;
|
||||
}
|
||||
|
||||
public boolean canConvert(TypeDescriptor sourceTypeDescriptor, TypeDescriptor targetTypeDescriptor) {
|
||||
if (conversionService.canConvert(sourceTypeDescriptor, targetTypeDescriptor)) {
|
||||
return true;
|
||||
}
|
||||
// TODO: what does this mean? This method is not used in SpEL so
|
||||
// probably ignorable?
|
||||
Class<?> sourceType = sourceTypeDescriptor.getObjectType();
|
||||
Class<?> targetType = targetTypeDescriptor.getObjectType();
|
||||
return canConvert(sourceType, targetType);
|
||||
}
|
||||
|
||||
public Object convertValue(Object value, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
// Echoes
|
||||
// org.springframework.expression.common.ExpressionUtils.convertTypedValue()
|
||||
if ((targetType.getType() == Void.class || targetType.getType() == Void.TYPE) && value == null) {
|
||||
return null;
|
||||
}
|
||||
if (sourceType != null) {
|
||||
Class<?> sourceClass = sourceType.getType();
|
||||
//Class<?> targetClass = targetType.getType();
|
||||
if (sourceType.isAssignableTo(targetType) && ClassUtils.isPrimitiveArray(sourceClass)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (conversionService.canConvert(sourceType, targetType)) {
|
||||
return conversionService.convert(value, sourceType, targetType);
|
||||
}
|
||||
if (!String.class.isAssignableFrom(sourceType.getType())) {
|
||||
PropertyEditor editor = delegate.findCustomEditor(sourceType.getType(), null);
|
||||
if (editor == null) {
|
||||
editor = this.getDefaultEditor(sourceType.getType());
|
||||
}
|
||||
if (editor != null) { // INT-1441
|
||||
String text = null;
|
||||
synchronized (editor) {
|
||||
editor.setValue(value);
|
||||
text = editor.getAsText();
|
||||
}
|
||||
if (String.class.isAssignableFrom(targetType.getType())) {
|
||||
return text;
|
||||
}
|
||||
return convertValue(text, TypeDescriptor.valueOf(String.class), targetType);
|
||||
}
|
||||
}
|
||||
return delegate.convertIfNecessary(value, targetType.getType());
|
||||
}
|
||||
|
||||
private PropertyEditor getDefaultEditor(Class<?> sourceType) {
|
||||
PropertyEditor defaultEditor;
|
||||
if (this.haveCalledDelegateGetDefaultEditor) {
|
||||
defaultEditor = delegate.getDefaultEditor(sourceType);
|
||||
} else {
|
||||
synchronized (this) {
|
||||
// not thread-safe - it builds the defaultEditors field in-place
|
||||
// (SPR-10191)
|
||||
defaultEditor = delegate.getDefaultEditor(sourceType);
|
||||
}
|
||||
this.haveCalledDelegateGetDefaultEditor = true;
|
||||
}
|
||||
return defaultEditor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.statemachine.ExtendedState;
|
||||
|
||||
/**
|
||||
* Default implementation of a {@link ExtendedState}.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public class DefaultExtendedState implements ExtendedState {
|
||||
|
||||
private final Map<String, Object> variables;
|
||||
|
||||
/**
|
||||
* Instantiates a new default extended state.
|
||||
*/
|
||||
public DefaultExtendedState() {
|
||||
this.variables = new HashMap<String, Object>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getVariables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.statemachine.ExtendedState;
|
||||
import org.springframework.statemachine.StateContext;
|
||||
|
||||
public class DefaultStateContext implements StateContext {
|
||||
|
||||
private final MessageHeaders messageHeaders;
|
||||
|
||||
private final ExtendedState extendedState;
|
||||
|
||||
public DefaultStateContext(MessageHeaders messageHeaders, ExtendedState extendedState) {
|
||||
this.messageHeaders = messageHeaders;
|
||||
this.extendedState = extendedState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageHeaders getMessageHeaders() {
|
||||
return messageHeaders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtendedState getExtendedState() {
|
||||
return extendedState;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.context.expression.MapAccessor;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardTypeConverter;
|
||||
|
||||
/**
|
||||
* Utility class with static methods for helping with establishing environments for
|
||||
* SpEL expressions.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public abstract class ExpressionUtils {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ExpressionUtils.class);
|
||||
|
||||
/**
|
||||
* Create a {@link StandardEvaluationContext} with a {@link MapAccessor} in its
|
||||
* property accessor property and the supplied {@link ConversionService} in its
|
||||
* conversionService property.
|
||||
*
|
||||
* @param conversionService the conversion service.
|
||||
* @return the evaluation context.
|
||||
*/
|
||||
private static StandardEvaluationContext createStandardEvaluationContext(ConversionService conversionService,
|
||||
BeanFactory beanFactory) {
|
||||
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
|
||||
evaluationContext.addPropertyAccessor(new MapAccessor());
|
||||
if (conversionService != null) {
|
||||
evaluationContext.setTypeConverter(new StandardTypeConverter(conversionService));
|
||||
}
|
||||
if (beanFactory != null) {
|
||||
evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
|
||||
}
|
||||
return evaluationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create a context with no BeanFactory, usually in tests.
|
||||
* @return The evaluation context.
|
||||
*/
|
||||
public static StandardEvaluationContext createStandardEvaluationContext() {
|
||||
return doCreateContext(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the context from the beanFactory if not null; emits a warning if the beanFactory
|
||||
* is null.
|
||||
* @param beanFactory The bean factory.
|
||||
* @return The evaluation context.
|
||||
*/
|
||||
public static StandardEvaluationContext createStandardEvaluationContext(BeanFactory beanFactory) {
|
||||
if (beanFactory == null) {
|
||||
logger.warn("Creating EvaluationContext with no beanFactory", new RuntimeException("No beanfactory"));
|
||||
}
|
||||
return doCreateContext(beanFactory);
|
||||
}
|
||||
|
||||
private static StandardEvaluationContext doCreateContext(BeanFactory beanFactory) {
|
||||
ConversionService conversionService = null;
|
||||
StandardEvaluationContext evaluationContext = null;
|
||||
if (beanFactory != null) {
|
||||
evaluationContext = StateMachineContextUtils.getEvaluationContext(beanFactory);
|
||||
}
|
||||
if (evaluationContext == null) {
|
||||
if (beanFactory != null) {
|
||||
conversionService = StateMachineContextUtils.getConversionService(beanFactory);
|
||||
}
|
||||
evaluationContext = createStandardEvaluationContext(conversionService, beanFactory);
|
||||
}
|
||||
return evaluationContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.expression.MethodFilter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link MethodFilter} implementation that will always return the same Method
|
||||
* instance within a single-element list if it is present in the candidate list.
|
||||
* If the Method is not present in the candidate list, it will return an empty
|
||||
* list.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Gary Russell
|
||||
* @author Janne Valkealahti
|
||||
*/
|
||||
public class FixedMethodFilter implements MethodFilter {
|
||||
|
||||
private final Method method;
|
||||
|
||||
public FixedMethodFilter(Method method) {
|
||||
Assert.notNull(method, "method must not be null");
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public List<Method> filter(List<Method> methods) {
|
||||
if (methods != null && methods.contains(this.method)) {
|
||||
List<Method> filteredList = new ArrayList<Method>(1);
|
||||
filteredList.add(this.method);
|
||||
return filteredList;
|
||||
}
|
||||
return Collections.<Method> emptyList();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Convenient base class for object which needs spring task scheduler, task
|
||||
* executor and life cycle handling.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public abstract class LifecycleObjectSupport implements InitializingBean, SmartLifecycle, BeanFactoryAware {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LifecycleObjectSupport.class);
|
||||
|
||||
// fields for lifecycle
|
||||
private volatile boolean autoStartup = true;
|
||||
private volatile int phase = 0;
|
||||
private volatile boolean running;
|
||||
|
||||
// lock to protect lifycycle methods
|
||||
private final ReentrantLock lifecycleLock = new ReentrantLock();
|
||||
|
||||
// common task handling
|
||||
private TaskScheduler taskScheduler;
|
||||
private TaskExecutor taskExecutor;
|
||||
|
||||
// to access bean factory
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
@Override
|
||||
public final void afterPropertiesSet() {
|
||||
try {
|
||||
this.onInit();
|
||||
} catch (Exception e) {
|
||||
if (e instanceof RuntimeException) {
|
||||
throw (RuntimeException) e;
|
||||
}
|
||||
throw new BeanInitializationException("failed to initialize", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
Assert.notNull(beanFactory, "beanFactory must not be null");
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug("Setting bean factory: " + beanFactory + " for " + this);
|
||||
}
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isAutoStartup() {
|
||||
return this.autoStartup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getPhase() {
|
||||
return this.phase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isRunning() {
|
||||
this.lifecycleLock.lock();
|
||||
try {
|
||||
return this.running;
|
||||
} finally {
|
||||
this.lifecycleLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void start() {
|
||||
this.lifecycleLock.lock();
|
||||
try {
|
||||
if (!this.running) {
|
||||
this.doStart();
|
||||
this.running = true;
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("started " + this);
|
||||
} else {
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug("already started " + this);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
this.lifecycleLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void stop() {
|
||||
this.lifecycleLock.lock();
|
||||
try {
|
||||
if (this.running) {
|
||||
this.doStop();
|
||||
this.running = false;
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("stopped " + this);
|
||||
}
|
||||
} else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("already stopped " + this);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
this.lifecycleLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void stop(Runnable callback) {
|
||||
this.lifecycleLock.lock();
|
||||
try {
|
||||
this.stop();
|
||||
callback.run();
|
||||
} finally {
|
||||
this.lifecycleLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the auto startup.
|
||||
*
|
||||
* @param autoStartup the new auto startup
|
||||
* @see SmartLifecycle
|
||||
*/
|
||||
public void setAutoStartup(boolean autoStartup) {
|
||||
this.autoStartup = autoStartup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the phase.
|
||||
*
|
||||
* @param phase the new phase
|
||||
* @see SmartLifecycle
|
||||
*/
|
||||
public void setPhase(int phase) {
|
||||
this.phase = phase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link BeanFactory} for this instance.
|
||||
*
|
||||
* @return the bean factory.
|
||||
*/
|
||||
protected final BeanFactory getBeanFactory() {
|
||||
return beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the used {@link TaskScheduler}.
|
||||
*
|
||||
* @param taskScheduler the task scheduler
|
||||
*/
|
||||
public void setTaskScheduler(TaskScheduler taskScheduler) {
|
||||
Assert.notNull(taskScheduler, "taskScheduler must not be null");
|
||||
this.taskScheduler = taskScheduler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the defined {@link TaskScheduler}.
|
||||
*
|
||||
* @return the defined task scheduler
|
||||
*/
|
||||
protected TaskScheduler getTaskScheduler() {
|
||||
if(taskScheduler == null && getBeanFactory() != null) {
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug("getting taskScheduler service from bean factory " + getBeanFactory());
|
||||
}
|
||||
taskScheduler = StateMachineContextUtils.getTaskScheduler(getBeanFactory());
|
||||
}
|
||||
return taskScheduler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the used {@link TaskExecutor}.
|
||||
*
|
||||
* @param taskExecutor the task executor
|
||||
*/
|
||||
public void setTaskExecutor(TaskExecutor taskExecutor) {
|
||||
Assert.notNull(taskExecutor, "taskExecutor must not be null");
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the defined {@link TaskExecutor}.
|
||||
*
|
||||
* @return the defined task executor
|
||||
*/
|
||||
protected TaskExecutor getTaskExecutor() {
|
||||
if(taskExecutor == null && getBeanFactory() != null) {
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug("getting taskExecutor service from bean factory " + getBeanFactory());
|
||||
}
|
||||
taskExecutor = StateMachineContextUtils.getTaskExecutor(getBeanFactory());
|
||||
}
|
||||
return taskExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may implement this for initialization logic. Called
|
||||
* during the {@link InitializingBean} phase. Implementor should
|
||||
* always call super method not to break initialization chain.
|
||||
*
|
||||
* @throws Exception exception
|
||||
*/
|
||||
protected void onInit() throws Exception {}
|
||||
|
||||
/**
|
||||
* Subclasses may implement this method with the start behavior. This
|
||||
* method will be invoked while holding the {@link #lifecycleLock}.
|
||||
*/
|
||||
protected void doStart() {};
|
||||
|
||||
/**
|
||||
* Subclasses may implement this method with the stop behavior. This method
|
||||
* will be invoked while holding the {@link #lifecycleLock}.
|
||||
*/
|
||||
protected void doStop() {};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Utility methods for accessing common components from the BeanFactory.
|
||||
*
|
||||
* @author Janne Valkealahti
|
||||
*
|
||||
*/
|
||||
public class StateMachineContextUtils {
|
||||
|
||||
/* Default task scheduler bean name */
|
||||
public static final String TASK_SCHEDULER_BEAN_NAME = "taskScheduler";
|
||||
|
||||
/* Default task executor bean name */
|
||||
public static final String TASK_EXECUTOR_BEAN_NAME = "taskExecutor";
|
||||
|
||||
/* Default conversion service bean name */
|
||||
public static final String CONVERSION_SERVICE_BEAN_NAME = "cloudClusterConversionService";
|
||||
|
||||
/* Default evaluation context bean name */
|
||||
public static final String EVALUATION_CONTEXT_BEAN_NAME = "cloudClusterEvaluationContext";
|
||||
|
||||
/**
|
||||
* Return the {@link TaskScheduler} bean whose name is "taskScheduler" if
|
||||
* available.
|
||||
*
|
||||
* @param beanFactory BeanFactory for lookup, must not be null.
|
||||
* @return task scheduler
|
||||
*/
|
||||
public static TaskScheduler getTaskScheduler(BeanFactory beanFactory) {
|
||||
return getBeanOfType(beanFactory, TASK_SCHEDULER_BEAN_NAME, TaskScheduler.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link TaskScheduler} bean whose name is "taskExecutor" if
|
||||
* available.
|
||||
*
|
||||
* @param beanFactory BeanFactory for lookup, must not be null.
|
||||
* @return task executor
|
||||
*/
|
||||
public static TaskExecutor getTaskExecutor(BeanFactory beanFactory) {
|
||||
return getBeanOfType(beanFactory, TASK_EXECUTOR_BEAN_NAME, TaskExecutor.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link ConversionService} bean whose name is
|
||||
* "yarnConversionService" if available.
|
||||
*
|
||||
* @param beanFactory
|
||||
* BeanFactory for lookup, must not be null.
|
||||
*
|
||||
* @return The {@link ConversionService} bean whose name is
|
||||
* "yarnConversionService" if available.
|
||||
*/
|
||||
public static ConversionService getConversionService(BeanFactory beanFactory) {
|
||||
return getBeanOfType(beanFactory, CONVERSION_SERVICE_BEAN_NAME, ConversionService.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link StandardEvaluationContext} bean whose name is
|
||||
* "yarnEvaluationContext" if available.
|
||||
*
|
||||
* @param beanFactory BeanFactory for lookup, must not be null.
|
||||
*
|
||||
* @return the instance of {@link StandardEvaluationContext} bean whose name
|
||||
* is "yarnEvaluationContext" .
|
||||
*/
|
||||
public static StandardEvaluationContext getEvaluationContext(BeanFactory beanFactory) {
|
||||
return getBeanOfType(beanFactory, EVALUATION_CONTEXT_BEAN_NAME, StandardEvaluationContext.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a bean from a factory with a given name and type.
|
||||
*
|
||||
* @param beanFactory the bean factory
|
||||
* @param beanName the bean name
|
||||
* @param type the type as of a class
|
||||
* @return Bean known to a bean factory, null if not found.
|
||||
*/
|
||||
private static <T> T getBeanOfType(BeanFactory beanFactory, String beanName, Class<T> type) {
|
||||
Assert.notNull(beanFactory, "BeanFactory must not be null");
|
||||
if (!beanFactory.containsBean(beanName)) {
|
||||
return null;
|
||||
}
|
||||
return beanFactory.getBean(beanName, type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.statemachine.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||
|
||||
/**
|
||||
* A {@link MethodFilter} implementation that will match unique methods.
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Janne Valkealahti
|
||||
*/
|
||||
public class UniqueMethodFilter implements MethodFilter {
|
||||
|
||||
private final List<Method> uniqueMethods = new ArrayList<Method>();
|
||||
|
||||
public UniqueMethodFilter(Class<?> targetClass) {
|
||||
ArrayList<Method> allMethods = new ArrayList<Method>(Arrays.asList(targetClass.getMethods()));
|
||||
for (Method method : allMethods) {
|
||||
this.uniqueMethods.add(org.springframework.util.ClassUtils.getMostSpecificMethod(method, targetClass));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean matches(Method method) {
|
||||
return this.uniqueMethods.contains(method);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user