package org.zstack.core.asyncbatch; import org.zstack.header.core.NoErrorCompletion; import org.zstack.utils.DebugUtils; import java.util.Collection; import java.util.Iterator; import java.util.concurrent.atomic.AtomicInteger; /** * Created by xing5 on 2017/3/5. */ public class While<T> { private Collection<T> items; private Do consumer; private int mode; private int step; private final int EACH = 1; private final int ALL = 2; private final int STEP = 3; public interface Do<T> { void accept(T item, NoErrorCompletion completion); } public While(Collection<T> items) { this.items = items; } public While each(Do<T> consumer) { mode = EACH; this.consumer = consumer; return this; } public While all(Do<T> consumer) { mode = ALL; this.consumer = consumer; return this; } private void run(Iterator<T> it, NoErrorCompletion completion) { if (!it.hasNext()) { completion.done(); return; } T t = it.next(); consumer.accept(t, new NoErrorCompletion(completion) { @Override public void done() { run(it, completion); } }); } public While step(Do<T> consumer, int step) { if (step < 0) { throw new IllegalArgumentException(String.format("step must be greater than zero, got %s", step)); } this.consumer = consumer; this.step = step; mode = STEP; return this; } public void run(NoErrorCompletion completion) { DebugUtils.Assert(consumer != null, "each() or all() or step() must be called before run()"); if (mode == EACH) { run(items.iterator(), completion); } else if (mode == ALL) { runAll(completion); } else if (mode == STEP) { runStep(completion); } else { DebugUtils.Assert(false, "should be here"); } } private void runStep(NoErrorCompletion completion) { int s = Math.min(step, items.size()); Iterator<T> it = items.iterator(); for (int i=0; i<s; i++) { runStep(it, completion); } } private void runStep(Iterator<T> it, NoErrorCompletion completion) { T t; synchronized (it) { if (!it.hasNext()) { completion.done(); return; } t = it.next(); } consumer.accept(t, new NoErrorCompletion(completion) { @Override public void done() { runStep(it, completion); } }); } private void runAll(NoErrorCompletion completion) { AtomicInteger count = new AtomicInteger(items.size()); if(count.intValue() == 0){ completion.done(); return; } for (T t : items) { consumer.accept(t, new NoErrorCompletion() { @Override public void done() { if (count.decrementAndGet() == 0) { completion.done(); } } }); } } }