package com.psddev.cms.db; import java.io.Closeable; import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import javax.servlet.http.HttpServletRequest; import com.psddev.dari.db.ForwardingDatabase; import com.psddev.dari.db.Query; import com.psddev.dari.db.State; import com.psddev.dari.util.PaginatedResult; public class AbDatabase extends ForwardingDatabase { private HttpServletRequest request; public HttpServletRequest getRequest() { return request; } public void setRequest(HttpServletRequest request) { this.request = request; } // --- ForwardingDatabase support --- private <T> T ab(T object) { if (object != null) { State state = State.getInstance(object); for (Map.Entry<String, AbVariationField> entry : state.as(AbVariationObject.class).getFields().entrySet()) { String fieldName = entry.getKey(); AbVariationField variationField = entry.getValue(); if (variationField == null) { continue; } List<AbVariation> variations = variationField.getVariations(); double total = 0.0; for (AbVariation variation : variations) { total += variation.getWeight(); } double accum = 0.0; double random = AbFilter.Static.random(getRequest(), state, fieldName); for (ListIterator<AbVariation> i = variations.listIterator(variations.size()); i.hasPrevious(); ) { AbVariation variation = i.previous(); accum += variation.getWeight(); if (random < accum / total) { state.put(fieldName, variation.getValue()); break; } } } } return object; } @Override public <T> List<T> readAll(Query<T> query) { List<T> all = super.readAll(query); for (T item : all) { ab(item); } return all; } @Override public <T> T readFirst(Query<T> query) { return ab(super.readFirst(query)); } @Override public <T> Iterable<T> readIterable(Query<T> query, int fetchSize) { return new FilteringIterable<T>(super.readIterable(query, fetchSize)); } private class FilteringIterable<E> implements Iterable<E> { private final Iterable<E> delegate; public FilteringIterable(Iterable<E> delegate) { this.delegate = delegate; } @Override public Iterator<E> iterator() { return new FilteringIterator<E>(delegate.iterator()); } } private class FilteringIterator<E> implements Closeable, Iterator<E> { private final Iterator<E> delegate; public FilteringIterator(Iterator<E> delegate) { this.delegate = delegate; } @Override public void close() throws IOException { if (delegate instanceof Closeable) { ((Closeable) delegate).close(); } } @Override public boolean hasNext() { return delegate.hasNext(); } @Override public E next() { return ab(delegate.next()); } @Override public void remove() { throw new UnsupportedOperationException(); } } @Override public <T> PaginatedResult<T> readPartial(Query<T> query, long offset, int limit) { PaginatedResult<T> result = super.readPartial(query, offset, limit); for (T item : result.getItems()) { ab(item); } return result; } // --- Deprecated --- @Deprecated @Override public <T> List<T> readList(Query<T> query) { List<T> list = super.readList(query); for (T item : list) { ab(item); } return list; } }