001/*
002 * Copyright 2017 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.Map;
020
021import org.neo4j.ogm.session.SessionFactory;
022
023import org.springframework.batch.item.data.Neo4jItemReader;
024import org.springframework.util.Assert;
025
026/**
027 * A builder for the {@link Neo4jItemReader}.
028 *
029 * @author Glenn Renfro
030 * @since 4.0
031 * @see Neo4jItemReader
032 */
033public class Neo4jItemReaderBuilder<T> {
034
035        private SessionFactory sessionFactory;
036
037        private String startStatement;
038
039        private String returnStatement;
040
041        private String matchStatement;
042
043        private String whereStatement;
044
045        private String orderByStatement;
046
047        private Class<T> targetType;
048
049        private Map<String, Object> parameterValues;
050
051        private int pageSize = 10;
052
053        private boolean saveState = true;
054
055        private String name;
056
057        private int maxItemCount = Integer.MAX_VALUE;
058
059        private int currentItemCount;
060
061        /**
062         * Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport}
063         * should be persisted within the {@link org.springframework.batch.item.ExecutionContext}
064         * for restart purposes.
065         *
066         * @param saveState defaults to true
067         * @return The current instance of the builder.
068         */
069        public Neo4jItemReaderBuilder<T> saveState(boolean saveState) {
070                this.saveState = saveState;
071
072                return this;
073        }
074
075        /**
076         * The name used to calculate the key within the
077         * {@link org.springframework.batch.item.ExecutionContext}. Required if
078         * {@link #saveState(boolean)} is set to true.
079         *
080         * @param name name of the reader instance
081         * @return The current instance of the builder.
082         * @see org.springframework.batch.item.ItemStreamSupport#setName(String)
083         */
084        public Neo4jItemReaderBuilder<T> name(String name) {
085                this.name = name;
086
087                return this;
088        }
089
090        /**
091         * Configure the max number of items to be read.
092         *
093         * @param maxItemCount the max items to be read
094         * @return The current instance of the builder.
095         * @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setMaxItemCount(int)
096         */
097        public Neo4jItemReaderBuilder<T> maxItemCount(int maxItemCount) {
098                this.maxItemCount = maxItemCount;
099
100                return this;
101        }
102
103        /**
104         * Index for the current item. Used on restarts to indicate where to start from.
105         *
106         * @param currentItemCount current index
107         * @return this instance for method chaining
108         * @see org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader#setCurrentItemCount(int)
109         */
110        public Neo4jItemReaderBuilder<T> currentItemCount(int currentItemCount) {
111                this.currentItemCount = currentItemCount;
112
113                return this;
114        }
115
116        /**
117         * Establish the session factory for the reader.
118         * @param sessionFactory the factory to use for the reader.
119         * @return this instance for method chaining
120         * @see Neo4jItemReader#setSessionFactory(SessionFactory)
121         */
122        public Neo4jItemReaderBuilder<T> sessionFactory(SessionFactory sessionFactory) {
123                this.sessionFactory = sessionFactory;
124
125                return this;
126        }
127
128        /**
129         * The number of items to be read with each page.
130         *
131         * @param pageSize the number of items
132         * @return this instance for method chaining
133         * @see Neo4jItemReader#setPageSize(int)
134         */
135        public Neo4jItemReaderBuilder<T> pageSize(int pageSize) {
136                this.pageSize = pageSize;
137
138                return this;
139        }
140
141        /**
142         * Optional parameters to be used in the cypher query.
143         *
144         * @param parameterValues the parameter values to be used in the cypher query
145         * @return this instance for method chaining
146         * @see Neo4jItemReader#setParameterValues(Map)
147         */
148        public Neo4jItemReaderBuilder<T> parameterValues(Map<String, Object> parameterValues) {
149                this.parameterValues = parameterValues;
150
151                return this;
152        }
153
154        /**
155         * The start segment of the cypher query. START is prepended to the statement provided
156         * and should <em>not</em> be included.
157         *
158         * @param startStatement the start fragment of the cypher query.
159         * @return this instance for method chaining
160         * @see Neo4jItemReader#setStartStatement(String)
161         */
162        public Neo4jItemReaderBuilder<T> startStatement(String startStatement) {
163                this.startStatement = startStatement;
164
165                return this;
166        }
167
168        /**
169         * The return statement of the cypher query. RETURN is prepended to the statement
170         * provided and should <em>not</em> be included
171         *
172         * @param returnStatement the return fragment of the cypher query.
173         * @return this instance for method chaining
174         * @see Neo4jItemReader#setReturnStatement(String)
175         */
176        public Neo4jItemReaderBuilder<T> returnStatement(String returnStatement) {
177                this.returnStatement = returnStatement;
178
179                return this;
180        }
181
182        /**
183         * An optional match fragment of the cypher query. MATCH is prepended to the statement
184         * provided and should <em>not</em> be included.
185         *
186         * @param matchStatement the match fragment of the cypher query
187         * @return this instance for method chaining
188         * @see Neo4jItemReader#setMatchStatement(String)
189         */
190        public Neo4jItemReaderBuilder<T> matchStatement(String matchStatement) {
191                this.matchStatement = matchStatement;
192
193                return this;
194        }
195
196        /**
197         * An optional where fragment of the cypher query. WHERE is prepended to the statement
198         * provided and should <em>not</em> be included.
199         *
200         * @param whereStatement where fragment of the cypher query
201         * @return this instance for method chaining
202         * @see Neo4jItemReader#setWhereStatement(String)
203         */
204        public Neo4jItemReaderBuilder<T> whereStatement(String whereStatement) {
205                this.whereStatement = whereStatement;
206
207                return this;
208        }
209
210        /**
211         * A list of properties to order the results by. This is required so that subsequent
212         * page requests pull back the segment of results correctly. ORDER BY is prepended to
213         * the statement provided and should <em>not</em> be included.
214         *
215         * @param orderByStatement order by fragment of the cypher query.
216         * @return this instance for method chaining
217         * @see Neo4jItemReader#setOrderByStatement(String)
218         */
219        public Neo4jItemReaderBuilder<T> orderByStatement(String orderByStatement) {
220                this.orderByStatement = orderByStatement;
221
222                return this;
223        }
224
225        /**
226         * The object type to be returned from each call to {@link Neo4jItemReader#read()}
227         *
228         * @param targetType the type of object to return.
229         * @return this instance for method chaining
230         * @see Neo4jItemReader#setTargetType(Class)
231         */
232        public Neo4jItemReaderBuilder<T> targetType(Class<T> targetType) {
233                this.targetType = targetType;
234
235                return this;
236        }
237
238        /**
239         * Returns a fully constructed {@link Neo4jItemReader}.
240         *
241         * @return a new {@link Neo4jItemReader}
242         */
243        public Neo4jItemReader<T> build() {
244                if (this.saveState) {
245                        Assert.hasText(this.name, "A name is required when saveState is set to true");
246                }
247                Assert.notNull(this.sessionFactory, "sessionFactory is required.");
248                Assert.notNull(this.targetType, "targetType is required.");
249                Assert.hasText(this.startStatement, "startStatement is required.");
250                Assert.hasText(this.returnStatement, "returnStatement is required.");
251                Assert.hasText(this.orderByStatement, "orderByStatement is required.");
252                Assert.isTrue(this.pageSize > 0, "pageSize must be greater than zero");
253                Assert.isTrue(this.maxItemCount > 0, "maxItemCount must be greater than zero");
254                Assert.isTrue(this.maxItemCount > this.currentItemCount , "maxItemCount must be greater than currentItemCount");
255
256                Neo4jItemReader<T> reader = new Neo4jItemReader<>();
257                reader.setMatchStatement(this.matchStatement);
258                reader.setOrderByStatement(this.orderByStatement);
259                reader.setPageSize(this.pageSize);
260                reader.setParameterValues(this.parameterValues);
261                reader.setSessionFactory(this.sessionFactory);
262                reader.setTargetType(this.targetType);
263                reader.setStartStatement(this.startStatement);
264                reader.setReturnStatement(this.returnStatement);
265                reader.setWhereStatement(this.whereStatement);
266                reader.setName(this.name);
267                reader.setSaveState(this.saveState);
268                reader.setCurrentItemCount(this.currentItemCount);
269                reader.setMaxItemCount(this.maxItemCount);
270
271                return reader;
272        }
273
274}