001/* 002 * Copyright 2006-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.springframework.batch.core.job.flow.support; 017 018import org.springframework.batch.core.ExitStatus; 019import org.springframework.batch.core.job.flow.State; 020import org.springframework.batch.support.PatternMatcher; 021import org.springframework.lang.Nullable; 022import org.springframework.util.Assert; 023import org.springframework.util.StringUtils; 024 025/** 026 * Value object representing a potential transition from one {@link State} to 027 * another. The originating State name and the next {@link State} to execute are 028 * linked by a pattern for the {@link ExitStatus#getExitCode() exit code} of an 029 * execution of the originating State. 030 * 031 * @author Dave Syer 032 * @author Michael Minella 033 * @author Mahmoud Ben Hassine 034 * @since 2.0 035 */ 036public final class StateTransition { 037 038 private final State state; 039 040 private final String pattern; 041 042 private final String next; 043 044 /** 045 * @return the pattern the {@link ExitStatus#getExitCode()} will be compared against. 046 */ 047 public String getPattern() { 048 return this.pattern; 049 } 050 051 /** 052 * Create a new end state {@link StateTransition} specification. This 053 * transition explicitly goes unconditionally to an end state (i.e. no more 054 * executions). 055 * 056 * @param state the {@link State} used to generate the outcome for this 057 * transition 058 * @return {@link StateTransition} that was created. 059 */ 060 public static StateTransition createEndStateTransition(State state) { 061 return createStateTransition(state, null, null); 062 } 063 064 /** 065 * Create a new end state {@link StateTransition} specification. This 066 * transition explicitly goes to an end state (i.e. no more processing) if 067 * the outcome matches the pattern. 068 * 069 * @param state the {@link State} used to generate the outcome for this 070 * transition 071 * @param pattern the pattern to match in the exit status of the 072 * {@link State} 073 * @return {@link StateTransition} that was created. 074 */ 075 public static StateTransition createEndStateTransition(State state, String pattern) { 076 return createStateTransition(state, pattern, null); 077 } 078 079 /** 080 * Convenience method to switch the origin and destination of a transition, 081 * creating a new instance. 082 * 083 * @param stateTransition an existing state transition 084 * @param state the new state for the origin 085 * @param next the new name for the destination 086 * 087 * @return {@link StateTransition} that was created. 088 */ 089 public static StateTransition switchOriginAndDestination(StateTransition stateTransition, State state, String next) { 090 return createStateTransition(state, stateTransition.pattern, next); 091 } 092 093 /** 094 * Create a new state {@link StateTransition} specification with a wildcard 095 * pattern that matches all outcomes. 096 * 097 * @param state the {@link State} used to generate the outcome for this 098 * transition 099 * @param next the name of the next {@link State} to execute 100 * @return {@link StateTransition} that was created. 101 */ 102 public static StateTransition createStateTransition(State state, String next) { 103 return createStateTransition(state, null, next); 104 } 105 106 /** 107 * Create a new {@link StateTransition} specification from one {@link State} 108 * to another (by name). 109 * 110 * @param state the {@link State} used to generate the outcome for this 111 * transition 112 * @param pattern the pattern to match in the exit status of the 113 * {@link State} (can be {@code null}) 114 * @param next the name of the next {@link State} to execute (can be {@code null}) 115 * @return {@link StateTransition} that was created. 116 */ 117 public static StateTransition createStateTransition(State state, @Nullable String pattern, @Nullable String next) { 118 return new StateTransition(state, pattern, next); 119 } 120 121 private StateTransition(State state, @Nullable String pattern, @Nullable String next) { 122 super(); 123 if (!StringUtils.hasText(pattern)) { 124 this.pattern = "*"; 125 } 126 else { 127 this.pattern = pattern; 128 } 129 130 Assert.notNull(state, "A state is required for a StateTransition"); 131 if (state.isEndState() && StringUtils.hasText(next)) { 132 throw new IllegalStateException("End state cannot have next: " + state); 133 } 134 135 this.next = next; 136 this.state = state; 137 } 138 139 /** 140 * Public getter for the State. 141 * @return the State 142 */ 143 public State getState() { 144 return state; 145 } 146 147 /** 148 * Public getter for the next State name. 149 * @return the next 150 */ 151 public String getNext() { 152 return next; 153 } 154 155 /** 156 * Check if the provided status matches the pattern, signalling that the 157 * next State should be executed. 158 * 159 * @param status the status to compare 160 * @return true if the pattern matches this status 161 */ 162 public boolean matches(String status) { 163 return PatternMatcher.match(pattern, status); 164 } 165 166 /** 167 * Check for a special next State signalling the end of a job. 168 * 169 * @return true if this transition goes nowhere (there is no next) 170 */ 171 public boolean isEnd() { 172 return next == null; 173 } 174 175 /* 176 * (non-Javadoc) 177 * 178 * @see java.lang.Object#toString() 179 */ 180 @Override 181 public String toString() { 182 return String.format("StateTransition: [state=%s, pattern=%s, next=%s]", 183 state == null ? null : state.getName(), pattern, next); 184 } 185 186}