001/* 002 * Copyright 2006-2013 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.listener; 017 018import org.springframework.batch.core.ExitStatus; 019import org.springframework.batch.core.Job; 020import org.springframework.batch.core.Step; 021import org.springframework.batch.core.StepExecution; 022import org.springframework.batch.item.ExecutionContext; 023import org.springframework.batch.support.PatternMatcher; 024import org.springframework.beans.factory.InitializingBean; 025import org.springframework.util.Assert; 026 027/** 028 * This class can be used to automatically promote items from the {@link Step} 029 * {@link ExecutionContext} to the {@link Job} {@link ExecutionContext} at the 030 * end of a step. A list of keys should be provided that correspond to the items 031 * in the {@link Step} {@link ExecutionContext} that should be promoted. 032 * 033 * Additionally, an optional list of statuses can be set to indicate for which 034 * exit status codes the promotion should occur. These statuses will be checked 035 * using the {@link PatternMatcher}, so wildcards are allowed. By default, 036 * promotion will only occur for steps with an exit code of "COMPLETED". 037 * 038 * @author Dan Garrette 039 * @since 2.0 040 */ 041public class ExecutionContextPromotionListener extends StepExecutionListenerSupport implements InitializingBean { 042 043 private String[] keys = null; 044 045 private String[] statuses = new String[] { ExitStatus.COMPLETED.getExitCode() }; 046 047 private boolean strict = false; 048 049 @Override 050 public ExitStatus afterStep(StepExecution stepExecution) { 051 ExecutionContext stepContext = stepExecution.getExecutionContext(); 052 ExecutionContext jobContext = stepExecution.getJobExecution().getExecutionContext(); 053 String exitCode = stepExecution.getExitStatus().getExitCode(); 054 for (String statusPattern : statuses) { 055 if (PatternMatcher.match(statusPattern, exitCode)) { 056 for (String key : keys) { 057 if (stepContext.containsKey(key)) { 058 jobContext.put(key, stepContext.get(key)); 059 } else { 060 if (strict) { 061 throw new IllegalArgumentException("The key [" + key 062 + "] was not found in the Step's ExecutionContext."); 063 } 064 } 065 } 066 break; 067 } 068 } 069 070 return null; 071 } 072 073 @Override 074 public void afterPropertiesSet() throws Exception { 075 Assert.notNull(this.keys, "The 'keys' property must be provided"); 076 Assert.notEmpty(this.keys, "The 'keys' property must not be empty"); 077 Assert.notNull(this.statuses, "The 'statuses' property must be provided"); 078 Assert.notEmpty(this.statuses, "The 'statuses' property must not be empty"); 079 } 080 081 /** 082 * @param keys A list of keys corresponding to items in the {@link Step} 083 * {@link ExecutionContext} that must be promoted. 084 */ 085 public void setKeys(String[] keys) { 086 this.keys = keys; 087 } 088 089 /** 090 * @param statuses A list of statuses for which the promotion should occur. 091 * Statuses can may contain wildcards recognizable by a 092 * {@link PatternMatcher}. 093 */ 094 public void setStatuses(String[] statuses) { 095 this.statuses = statuses; 096 } 097 098 /** 099 * If set to TRUE, the listener will throw an exception if any 'key' is not 100 * found in the Step {@link ExecutionContext}. FALSE by default. 101 * 102 * @param strict boolean the value of the flag. 103 */ 104 public void setStrict(boolean strict) { 105 this.strict = strict; 106 } 107 108}