package fr.openwide.core.wicket.more.util.model; import java.util.Collection; import java.util.List; import java.util.Objects; import org.apache.wicket.model.AbstractReadOnlyModel; import org.apache.wicket.model.IModel; import com.google.common.base.Function; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; public abstract class StreamModel<T> extends AbstractReadOnlyModel<Iterable<T>> { private static final long serialVersionUID = -1713424773189633187L; public static <T> StreamModel<T> of(final IModel<? extends Iterable<T>> model) { Objects.requireNonNull(model); return new StreamModel<T>() { private static final long serialVersionUID = 1L; @Override public Iterable<T> getObject() { return model.getObject(); } @Override public void detach() { super.detach(); Detachables.detach(model); } }; } private StreamModel() { } public final StreamModel<T> concat(IModel<? extends Iterable<? extends T>> firstModel) { return concat(this, firstModel); } @SafeVarargs public final StreamModel<T> concat(IModel<? extends Iterable<? extends T>> firstModel, IModel<? extends Iterable<? extends T>>... otherModels) { return new ConcatStreamModel(firstModel, otherModels); } private class ConcatStreamModel extends StreamModel<T> { private static final long serialVersionUID = 1L; private final List<IModel<? extends Iterable<? extends T>>> models; @SafeVarargs public ConcatStreamModel(IModel<? extends Iterable<? extends T>> firstModel, IModel<? extends Iterable<? extends T>>... otherModels) { super(); this.models = ImmutableList.<IModel<? extends Iterable<? extends T>>>builder() .add(StreamModel.this) .add(firstModel) .add(otherModels) .build(); } @Override public Iterable<T> getObject() { return Iterables.concat( Iterables.transform( models, Models.<Iterable<? extends T>>getObject() ) ); } @Override public void detach() { super.detach(); Detachables.detach(models); } } public <S> StreamModel<S> map(Function<? super T, S> function) { return new MapStreamModel<>(function); } private class MapStreamModel<S> extends StreamModel<S> { private static final long serialVersionUID = 1L; private final Function<? super T, S> function; public MapStreamModel(Function<? super T, S> function) { super(); this.function = Objects.requireNonNull(function); } @Override public Iterable<S> getObject() { return Iterables.transform( StreamModel.this.getObject(), function ); } @Override public void detach() { super.detach(); Detachables.detach(StreamModel.this); } } public <C extends Collection<T>> IModel<C> collect(Supplier<? extends C> supplier) { return new CollectModel<>(supplier); } private class CollectModel<C extends Collection<T>> extends AbstractReadOnlyModel<C> { private static final long serialVersionUID = 1L; private final Supplier<? extends C> supplier; public CollectModel(Supplier<? extends C> supplier) { super(); this.supplier = Objects.requireNonNull(supplier); } @Override public C getObject() { C collection = supplier.get(); Iterables.addAll(collection, StreamModel.this.getObject()); return collection; } @Override public void detach() { super.detach(); Detachables.detach(StreamModel.this); } } public IModel<T> first() { return new FirstModel(); } private class FirstModel extends AbstractReadOnlyModel<T> { private static final long serialVersionUID = 1L; @Override public T getObject() { return Iterables.getFirst(StreamModel.this.getObject(), null); } @Override public void detach() { super.detach(); Detachables.detach(StreamModel.this); } } }