class RepeatOperationsInterceptor implements MethodInterceptor {

	private RepeatOperations repeatOperations = new RepeatTemplate();

	/**
	 * Setter for the {@link RepeatOperations}.
	 * @param batchTemplate template to be used
	 * @throws IllegalArgumentException if the argument is null.
	 */
	public void setRepeatOperations(RepeatOperations batchTemplate) {
		Assert.notNull(batchTemplate, "'repeatOperations' cannot be null.");
		this.repeatOperations = batchTemplate;
	}

	/**
	 * Invoke the proceeding method call repeatedly, according to the properties of the
	 * injected {@link RepeatOperations}.
	 *
	 * @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
	 */
	@Override
	public Object invoke(final MethodInvocation invocation) throws Throwable {<FILL_FUNCTION_BODY>}

	private boolean isComplete(Object result) {
		return result == null || (result instanceof Boolean) && !(Boolean) result;
	}

	/**
	 * Simple wrapper exception class to enable nasty errors to be passed out of the scope
	 * of the repeat operations and handled by the caller.
	 *
	 * @author Dave Syer
	 *
	 */
	private static class RepeatOperationsInterceptorException extends RepeatException {

		public RepeatOperationsInterceptorException(String message, Throwable e) {
			super(message, e);
		}

	}

	/**
	 * Simple wrapper object for the result from a method invocation.
	 *
	 * @author Dave Syer
	 *
	 */
	private static class ResultHolder {

		private Object value = null;

		private boolean ready = false;

		/**
		 * Public setter for the Object.
		 * @param value the value to set
		 */
		public void setValue(Object value) {
			this.ready = true;
			this.value = value;
		}

		public void setFinalValue(Object value) {
			if (ready) {
				// Only set the value the last time if the last time was also
				// the first time
				return;
			}
			setValue(value);
		}

		/**
		 * Public getter for the Object.
		 * @return the value
		 */
		public Object getValue() {
			return value;
		}

		/**
		 * @return true if a value has been set
		 */
		public boolean isReady() {
			return ready;
		}

	}

}


		final ResultHolder result = new ResultHolder();
		// Cache void return value if intercepted method returns void
		final boolean voidReturnType = Void.TYPE.equals(invocation.getMethod().getReturnType());
		if (voidReturnType) {
			// This will be ignored anyway, but we want it to be non-null for
			// convenience of checking that there is a result.
			result.setValue(new Object());
		}

		try {
			repeatOperations.iterate(context -> {
				try {

					MethodInvocation clone = invocation;
					if (invocation instanceof ProxyMethodInvocation) {
						clone = ((ProxyMethodInvocation) invocation).invocableClone();
					}
					else {
						throw new IllegalStateException(
								"MethodInvocation of the wrong type detected - this should not happen with Spring AOP, so please raise an issue if you see this exception");
					}

					Object value = clone.proceed();
					if (voidReturnType) {
						return RepeatStatus.CONTINUABLE;
					}
					if (!isComplete(value)) {
						// Save the last result
						result.setValue(value);
						return RepeatStatus.CONTINUABLE;
					}
					else {
						result.setFinalValue(value);
						return RepeatStatus.FINISHED;
					}
				}
				catch (Throwable e) {
					if (e instanceof Exception) {
						throw (Exception) e;
					}
					else {
						throw new RepeatOperationsInterceptorException("Unexpected error in batch interceptor", e);
					}
				}
			});
		}
		catch (Throwable t) {
			// The repeat exception should be unwrapped by the template
			throw t;
		}

		if (result.isReady()) {
			return result.getValue();
		}

		// No result means something weird happened
		throw new IllegalStateException("No result available for attempted repeat call to " + invocation
				+ ".  The invocation was never called, so maybe there is a problem with the completion policy?");
	
<no_super_class>