001/* 002 * Copyright 2017-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.item.data.builder; 018 019import java.util.List; 020import java.util.Map; 021 022import org.springframework.batch.item.data.MongoItemReader; 023import org.springframework.data.domain.Sort; 024import org.springframework.data.mongodb.core.MongoOperations; 025import org.springframework.data.mongodb.core.query.Query; 026import org.springframework.util.Assert; 027import org.springframework.util.StringUtils; 028 029/** 030 * A builder implementation for the {@link MongoItemReader} 031 * 032 * @author Glenn Renfro 033 * @author Mahmoud Ben Hassine 034 * @since 4.0 035 * @see MongoItemReader 036 */ 037public class MongoItemReaderBuilder<T> { 038 private MongoOperations template; 039 040 private String jsonQuery; 041 042 private Class<? extends T> targetType; 043 044 Map<String, Sort.Direction> sorts; 045 046 private String hint; 047 048 private String fields; 049 050 private String collection; 051 052 private List<Object> parameterValues; 053 054 protected int pageSize = 10; 055 056 private boolean saveState = true; 057 058 private String name; 059 060 private int maxItemCount = Integer.MAX_VALUE; 061 062 private int currentItemCount; 063 064 private Query query; 065 066 /** 067 * Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport} 068 * should be persisted within the {@link org.springframework.batch.item.ExecutionContext} 069 * for restart purposes. 070 * 071 * @param saveState defaults to true 072 * @return The current instance of the builder. 073 */ 074 public MongoItemReaderBuilder<T> saveState(boolean saveState) { 075 this.saveState = saveState; 076 077 return this; 078 } 079 080 /** 081 * The name used to calculate the key within the 082 * {@link org.springframework.batch.item.ExecutionContext}. Required if 083 * {@link #saveState(boolean)} is set to true. 084 * 085 * @param name name of the reader instance 086 * @return The current instance of the builder. 087 * @see org.springframework.batch.item.ItemStreamSupport#setName(String) 088 */ 089 public MongoItemReaderBuilder<T> name(String name) { 090 this.name = name; 091 092 return this; 093 } 094 095 /** 096 * Configure the max number of items to be read. 097 * 098 * @param maxItemCount the max items to be read 099 * @return The current instance of the builder. 100 * @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int) 101 */ 102 public MongoItemReaderBuilder<T> maxItemCount(int maxItemCount) { 103 this.maxItemCount = maxItemCount; 104 105 return this; 106 } 107 108 /** 109 * Index for the current item. Used on restarts to indicate where to start from. 110 * 111 * @param currentItemCount current index 112 * @return this instance for method chaining 113 * @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int) 114 */ 115 public MongoItemReaderBuilder<T> currentItemCount(int currentItemCount) { 116 this.currentItemCount = currentItemCount; 117 118 return this; 119 } 120 121 /** 122 * Used to perform operations against the MongoDB instance. Also handles the mapping 123 * of documents to objects. 124 * 125 * @param template the MongoOperations instance to use 126 * @see MongoOperations 127 * @return The current instance of the builder 128 * @see MongoItemReader#setTemplate(MongoOperations) 129 */ 130 public MongoItemReaderBuilder<T> template(MongoOperations template) { 131 this.template = template; 132 133 return this; 134 } 135 136 /** 137 * A JSON formatted MongoDB jsonQuery. Parameterization of the provided jsonQuery is allowed 138 * via ?<index> placeholders where the <index> indicates the index of the 139 * parameterValue to substitute. 140 * 141 * @param query JSON formatted Mongo jsonQuery 142 * @return The current instance of the builder 143 * @see MongoItemReader#setQuery(String) 144 */ 145 public MongoItemReaderBuilder<T> jsonQuery(String query) { 146 this.jsonQuery = query; 147 148 return this; 149 } 150 151 /** 152 * The type of object to be returned for each {@link MongoItemReader#read()} call. 153 * 154 * @param targetType the type of object to return 155 * @return The current instance of the builder 156 * @see MongoItemReader#setTargetType(Class) 157 */ 158 public MongoItemReaderBuilder<T> targetType(Class<? extends T> targetType) { 159 this.targetType = targetType; 160 161 return this; 162 } 163 164 /** 165 * {@link List} of values to be substituted in for each of the parameters in the 166 * query. 167 * 168 * @param parameterValues values 169 * @return The current instance of the builder 170 * @see MongoItemReader#setParameterValues(List) 171 */ 172 public MongoItemReaderBuilder<T> parameterValues(List<Object> parameterValues) { 173 this.parameterValues = parameterValues; 174 175 return this; 176 } 177 178 /** 179 * JSON defining the fields to be returned from the matching documents by MongoDB. 180 * 181 * @param fields JSON string that identifies the fields to sort by. 182 * @return The current instance of the builder 183 * @see MongoItemReader#setFields(String) 184 */ 185 public MongoItemReaderBuilder<T> fields(String fields) { 186 this.fields = fields; 187 188 return this; 189 } 190 191 /** 192 * {@link Map} of property 193 * names/{@link org.springframework.data.domain.Sort.Direction} values to sort the 194 * input by. 195 * 196 * @param sorts map of properties and direction to sort each. 197 * @return The current instance of the builder 198 * @see MongoItemReader#setSort(Map) 199 */ 200 public MongoItemReaderBuilder<T> sorts(Map<String, Sort.Direction> sorts) { 201 this.sorts = sorts; 202 203 return this; 204 } 205 206 /** 207 * Establish an optional collection that can be queried. 208 * 209 * @param collection Mongo collection to be queried. 210 * @return The current instance of the builder 211 * @see MongoItemReader#setCollection(String) 212 */ 213 public MongoItemReaderBuilder<T> collection(String collection) { 214 this.collection = collection; 215 216 return this; 217 } 218 219 /** 220 * JSON String telling MongoDB what index to use. 221 * 222 * @param hint string indicating what index to use. 223 * @return The current instance of the builder 224 * @see MongoItemReader#setHint(String) 225 */ 226 public MongoItemReaderBuilder<T> hint(String hint) { 227 this.hint = hint; 228 229 return this; 230 } 231 232 /** 233 * The number of items to be read with each page. 234 * 235 * @param pageSize the number of items 236 * @return this instance for method chaining 237 * @see MongoItemReader#setPageSize(int) 238 */ 239 public MongoItemReaderBuilder<T> pageSize(int pageSize) { 240 this.pageSize = pageSize; 241 242 return this; 243 } 244 245 /** 246 * Provide a Spring Data Mongo {@link Query}. This will take precedence over a JSON 247 * configured query. 248 * 249 * @param query Query to execute 250 * @return this instance for method chaining 251 * @see MongoItemReader#setQuery(Query) 252 */ 253 public MongoItemReaderBuilder<T> query(Query query) { 254 this.query = query; 255 256 return this; 257 } 258 259 /** 260 * Validates and builds a {@link MongoItemReader}. 261 * 262 * @return a {@link MongoItemReader} 263 */ 264 public MongoItemReader<T> build() { 265 Assert.notNull(this.template, "template is required."); 266 if (this.saveState) { 267 Assert.hasText(this.name, "A name is required when saveState is set to true"); 268 } 269 Assert.notNull(this.targetType, "targetType is required."); 270 Assert.state(StringUtils.hasText(this.jsonQuery) || this.query != null, "A query is required"); 271 272 if(StringUtils.hasText(this.jsonQuery)) { 273 Assert.notNull(this.sorts, "sorts map is required."); 274 } 275 else { 276 Assert.state(this.query.getLimit() != 0, "PageSize in Query object was ignored."); 277 } 278 279 MongoItemReader<T> reader = new MongoItemReader<>(); 280 reader.setTemplate(this.template); 281 reader.setTargetType(this.targetType); 282 reader.setQuery(this.jsonQuery); 283 reader.setSort(this.sorts); 284 reader.setHint(this.hint); 285 reader.setFields(this.fields); 286 reader.setCollection(this.collection); 287 reader.setParameterValues(this.parameterValues); 288 reader.setQuery(this.query); 289 290 reader.setPageSize(this.pageSize); 291 reader.setName(this.name); 292 reader.setSaveState(this.saveState); 293 reader.setCurrentItemCount(this.currentItemCount); 294 reader.setMaxItemCount(this.maxItemCount); 295 296 return reader; 297 } 298}