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 */ 016 017package org.springframework.batch.core; 018 019import java.util.Date; 020import java.util.HashMap; 021import java.util.LinkedHashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Properties; 025 026import org.springframework.batch.core.explore.JobExplorer; 027import org.springframework.util.Assert; 028 029/** 030 * Helper class for creating {@link JobParameters}. Useful because all 031 * {@link JobParameter} objects are immutable, and must be instantiated separately 032 * to ensure type safety. Once created, it can be used in the 033 * same was a java.lang.StringBuilder (except, order is irrelevant), by adding 034 * various parameter types and creating a valid {@link JobParameters} once 035 * finished.<br> 036 * <br> 037 * Using the identifying flag indicates if the parameter will be used 038 * in the identification of a JobInstance. That flag defaults to true. 039 * 040 * @author Lucas Ward 041 * @author Michael Minella 042 * @author Glenn Renfro 043 * @author Mahmoud Ben Hassine 044 * @since 1.0 045 * @see JobParameters 046 * @see JobParameter 047 */ 048public class JobParametersBuilder { 049 050 private Map<String, JobParameter> parameterMap; 051 052 private JobExplorer jobExplorer; 053 054 /** 055 * Default constructor. Initializes the builder with empty parameters. 056 */ 057 public JobParametersBuilder() { 058 this.parameterMap = new LinkedHashMap<>(); 059 } 060 061 /** 062 * @param jobExplorer {@link JobExplorer} used for looking up previous job parameter information 063 */ 064 public JobParametersBuilder(JobExplorer jobExplorer) { 065 this.jobExplorer = jobExplorer; 066 this.parameterMap = new LinkedHashMap<>(); 067 } 068 069 /** 070 * Copy constructor. Initializes the builder with the supplied parameters. 071 * @param jobParameters {@link JobParameters} instance used to initialize the builder. 072 */ 073 public JobParametersBuilder(JobParameters jobParameters) { 074 this(jobParameters, null); 075 } 076 077 /** 078 * Constructor to add conversion capabilities to support JSR-352. Per the spec, it is expected that all 079 * keys and values in the provided {@link Properties} instance are Strings 080 * 081 * @param properties the job parameters to be used 082 */ 083 public JobParametersBuilder(Properties properties) { 084 this.parameterMap = new LinkedHashMap<>(); 085 086 if(properties != null) { 087 for (Map.Entry<Object, Object> curProperty : properties.entrySet()) { 088 this.parameterMap.put((String) curProperty.getKey(), new JobParameter((String) curProperty.getValue(), false)); 089 } 090 } 091 } 092 093 /** 094 * Copy constructor. Initializes the builder with the supplied parameters. 095 * @param jobParameters {@link JobParameters} instance used to initialize the builder. 096 * @param jobExplorer {@link JobExplorer} used for looking up previous job parameter information 097 */ 098 public JobParametersBuilder(JobParameters jobParameters, JobExplorer jobExplorer) { 099 this.jobExplorer = jobExplorer; 100 this.parameterMap = new LinkedHashMap<>(jobParameters.getParameters()); 101 } 102 103 /** 104 * Add a new identifying String parameter for the given key. 105 * 106 * @param key - parameter accessor. 107 * @param parameter - runtime parameter 108 * @return a reference to this object. 109 */ 110 public JobParametersBuilder addString(String key, String parameter) { 111 this.parameterMap.put(key, new JobParameter(parameter, true)); 112 return this; 113 } 114 115 /** 116 * Add a new String parameter for the given key. 117 * 118 * @param key - parameter accessor. 119 * @param parameter - runtime parameter 120 * @param identifying - indicates if the parameter is used as part of identifying a job instance 121 * @return a reference to this object. 122 */ 123 public JobParametersBuilder addString(String key, String parameter, boolean identifying) { 124 this.parameterMap.put(key, new JobParameter(parameter, identifying)); 125 return this; 126 } 127 128 /** 129 * Add a new identifying {@link Date} parameter for the given key. 130 * 131 * @param key - parameter accessor. 132 * @param parameter - runtime parameter 133 * @return a reference to this object. 134 */ 135 public JobParametersBuilder addDate(String key, Date parameter) { 136 this.parameterMap.put(key, new JobParameter(parameter, true)); 137 return this; 138 } 139 140 /** 141 * Add a new {@link Date} parameter for the given key. 142 * 143 * @param key - parameter accessor. 144 * @param parameter - runtime parameter 145 * @param identifying - indicates if the parameter is used as part of identifying a job instance 146 * @return a reference to this object. 147 */ 148 public JobParametersBuilder addDate(String key, Date parameter, boolean identifying) { 149 this.parameterMap.put(key, new JobParameter(parameter, identifying)); 150 return this; 151 } 152 153 /** 154 * Add a new identifying Long parameter for the given key. 155 * 156 * @param key - parameter accessor. 157 * @param parameter - runtime parameter 158 * @return a reference to this object. 159 */ 160 public JobParametersBuilder addLong(String key, Long parameter) { 161 this.parameterMap.put(key, new JobParameter(parameter, true)); 162 return this; 163 } 164 165 /** 166 * Add a new Long parameter for the given key. 167 * 168 * @param key - parameter accessor. 169 * @param parameter - runtime parameter 170 * @param identifying - indicates if the parameter is used as part of identifying a job instance 171 * @return a reference to this object. 172 */ 173 public JobParametersBuilder addLong(String key, Long parameter, boolean identifying) { 174 this.parameterMap.put(key, new JobParameter(parameter, identifying)); 175 return this; 176 } 177 178 /** 179 * Add a new identifying Double parameter for the given key. 180 * 181 * @param key - parameter accessor. 182 * @param parameter - runtime parameter 183 * @return a reference to this object. 184 */ 185 public JobParametersBuilder addDouble(String key, Double parameter) { 186 this.parameterMap.put(key, new JobParameter(parameter, true)); 187 return this; 188 } 189 190 /** 191 * Add a new Double parameter for the given key. 192 * 193 * @param key - parameter accessor. 194 * @param parameter - runtime parameter 195 * @param identifying - indicates if the parameter is used as part of identifying a job instance 196 * @return a reference to this object. 197 */ 198 public JobParametersBuilder addDouble(String key, Double parameter, boolean identifying) { 199 this.parameterMap.put(key, new JobParameter(parameter, identifying)); 200 return this; 201 } 202 203 /** 204 * Conversion method that takes the current state of this builder and 205 * returns it as a JobParameters object. 206 * 207 * @return a valid {@link JobParameters} object. 208 */ 209 public JobParameters toJobParameters() { 210 return new JobParameters(this.parameterMap); 211 } 212 213 /** 214 * Add a new {@link JobParameter} for the given key. 215 * 216 * @param key - parameter accessor 217 * @param jobParameter - runtime parameter 218 * @return a reference to this object. 219 */ 220 public JobParametersBuilder addParameter(String key, JobParameter jobParameter) { 221 Assert.notNull(jobParameter, "JobParameter must not be null"); 222 this.parameterMap.put(key, jobParameter); 223 return this; 224 } 225 226 /** 227 * Copy job parameters into the current state. 228 * @param jobParameters parameters to copy in 229 * @return a reference to this object. 230 */ 231 public JobParametersBuilder addJobParameters(JobParameters jobParameters) { 232 Assert.notNull(jobParameters, "jobParameters must not be null"); 233 234 this.parameterMap.putAll(jobParameters.getParameters()); 235 236 return this; 237 } 238 239 /** 240 * Initializes the {@link JobParameters} based on the state of the {@link Job}. This 241 * should be called after all parameters have been entered into the builder. 242 * All parameters already set on this builder instance will be appended to 243 * those retrieved from the job incrementer, overriding any with the same key (Same 244 * behaviour as {@link org.springframework.batch.core.launch.support.CommandLineJobRunner} 245 * with "-next" option and {@link org.springframework.batch.core.launch.JobOperator#startNextInstance(String)}) 246 * 247 * @param job the job for which the {@link JobParameters} are being constructed. 248 * @return a reference to this object. 249 * 250 * @since 4.0 251 */ 252 public JobParametersBuilder getNextJobParameters(Job job) { 253 Assert.state(this.jobExplorer != null, "A JobExplorer is required to get next job parameters"); 254 Assert.notNull(job, "Job must not be null"); 255 Assert.notNull(job.getJobParametersIncrementer(), "No job parameters incrementer found for job=" + job.getName()); 256 257 String name = job.getName(); 258 JobParameters nextParameters; 259 List<JobInstance> lastInstances = this.jobExplorer.getJobInstances(name, 0, 1); 260 JobParametersIncrementer incrementer = job.getJobParametersIncrementer(); 261 if (lastInstances.isEmpty()) { 262 // Start from a completely clean sheet 263 nextParameters = incrementer.getNext(new JobParameters()); 264 } 265 else { 266 List<JobExecution> previousExecutions = this.jobExplorer.getJobExecutions(lastInstances.get(0)); 267 if (previousExecutions.isEmpty()) { 268 // Normally this will not happen - an instance exists with no executions 269 nextParameters = incrementer.getNext(new JobParameters()); 270 } 271 else { 272 JobExecution previousExecution = previousExecutions.get(0); 273 nextParameters = incrementer.getNext(previousExecution.getJobParameters()); 274 } 275 } 276 277 // start with parameters from the incrementer 278 Map<String, JobParameter> nextParametersMap = new HashMap<>(nextParameters.getParameters()); 279 // append new parameters (overriding those with the same key) 280 nextParametersMap.putAll(this.parameterMap); 281 this.parameterMap = nextParametersMap; 282 return this; 283 } 284}