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}