
org.sfm.map.MappingContextFactoryBuilder Maven / Gradle / Ivy
package org.sfm.map;
import org.sfm.jdbc.impl.BreakDetector;
import org.sfm.reflect.Getter;
import org.sfm.reflect.meta.ListElementPropertyMeta;
import org.sfm.reflect.meta.PropertyMeta;
import org.sfm.utils.BooleanProvider;
import org.sfm.utils.ErrorHelper;
import org.sfm.utils.Predicate;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MappingContextFactoryBuilder {
private final Counter counter;
private final int currentIndex;
private final MappingContextFactoryBuilder parent;
private final List keys;
private final KeySourceGetter keySourceGetter;
private final List> children = new ArrayList>();
private final PropertyMeta, ?> owner;
public MappingContextFactoryBuilder(KeySourceGetter keySourceGetter) {
this(new Counter(), new ArrayList(), keySourceGetter, null, null);
}
protected MappingContextFactoryBuilder(Counter counter, List keys, KeySourceGetter keySourceGetter, MappingContextFactoryBuilder parent, PropertyMeta, ?> owner) {
this.counter = counter;
this.currentIndex = counter.value;
this.keys = keys;
this.keySourceGetter = keySourceGetter;
this.parent = parent;
this.counter.value++;
this.owner = owner;
}
public void addKey(K key) {
if (!keys.contains(key)) {
keys.add(key);
}
}
public Predicate nullChecker() {
return new NullChecker(keys, keySourceGetter);
}
public Getter, BooleanProvider> breakDetectorGetter() {
if (isEmpty()) {
if (parent != null) {
return parent.breakDetectorGetter();
} else {
return new RootGetterProvider();
}
} else {
return new BreakGetter(currentIndex);
}
}
public MappingContextFactoryBuilder newBuilder(List subKeys, PropertyMeta, ?> owner) {
MappingContextFactoryBuilder subBuilder = new MappingContextFactoryBuilder(counter, subKeys, keySourceGetter, this, owner);
children.add(subBuilder);
return subBuilder;
}
@SuppressWarnings("unchecked")
public MappingContextFactory newFactory() {
if (parent != null) {
throw new IllegalStateException();
}
List> builders = getAllBuilders();
if (builders.isEmpty()) {
return new MappingContextFactoryImpl(new BreakDetector[0], null);
}
@SuppressWarnings("unchecked")
BreakDetector[] breakDetectors = new BreakDetector[builders.get(builders.size() -1).currentIndex + 1];
BreakDetector rootDetector = null;
for(int i = 0; i < builders.size(); i++) {
final MappingContextFactoryBuilder builder = builders.get(i);
BreakDetector parent = null;
int parentIndex = builder.getParentNonEmptyIndex();
if (parentIndex != -1) {
parent = breakDetectors[parentIndex];
}
final BreakDetector detector = builder.newBreakDetector(parent);
breakDetectors[builder.currentIndex] = detector;
if (builder.currentIndex == 0 || (rootDetector == null && builder.isRootEligible())) {
rootDetector = detector;
}
}
return new MappingContextFactoryImpl(breakDetectors, rootDetector);
}
private boolean isRootEligible() {
return !(owner instanceof ListElementPropertyMeta) && (parent == null || parent.isRootEligible());
}
private int getParentNonEmptyIndex() {
if (parent == null) {
return -1;
} else {
if (parent.isEmpty()) {
return parent.getParentNonEmptyIndex();
} else {
return parent.currentIndex;
}
}
}
private BreakDetector newBreakDetector(BreakDetector parent) {
return new BreakDetectorImpl(keys, keySourceGetter, parent);
}
private List> getAllBuilders() {
List> list = new ArrayList>();
if (!isEmpty()) {
list.add(this);
}
for(MappingContextFactoryBuilder child : children) {
list.addAll(child.getAllBuilders());
}
return list;
}
public boolean isEmpty() {
return keys.isEmpty();
}
public boolean hasNoDependentKeys() {
if (!isEmpty()) {
return false;
}
for(MappingContextFactoryBuilder builder : children) {
if (!builder.hasNoDependentKeys()) {
return false;
}
}
return true;
}
public boolean isRoot() {
return parent == null;
}
private static class Counter {
int value;
}
private static class BreakGetter implements Getter, BooleanProvider> {
private final int index;
private BreakGetter(int index) {
this.index = index;
}
@Override
public BooleanProvider get(MappingContext target) throws Exception {
return new MappingContextBooleanProvider(target, index);
}
}
private static class RootGetterProvider implements Getter, BooleanProvider> {
@Override
public BooleanProvider get(MappingContext target) throws Exception {
return new RootBooleanProvider(target);
}
}
private static class RootBooleanProvider implements BooleanProvider {
private final MappingContext target;
public RootBooleanProvider(MappingContext target) {
this.target = target;
}
@Override
public boolean getBoolean() {
return target == null || target.rootBroke();
}
}
private static class MappingContextBooleanProvider implements BooleanProvider {
private final MappingContext target;
private final int index;
public MappingContextBooleanProvider(MappingContext target, int index) {
this.target = target;
this.index = index;
}
@Override
public boolean getBoolean() {
return target == null || target.broke(index);
}
}
private static class NullChecker implements Predicate {
private final List keys;
private final KeySourceGetter keySourceGetter;
private NullChecker(List keys, KeySourceGetter keySourceGetter) {
this.keys = keys;
this.keySourceGetter = keySourceGetter;
}
@Override
public boolean test(S s) {
try {
if (keys.isEmpty()) return false;
for (int i = 0; i < keys.size(); i++) {
if (keySourceGetter.getValue(keys.get(i), s) != null) {
return false;
}
}
return true;
} catch(Exception e) {
ErrorHelper.rethrow(e);
throw new IllegalStateException();
}
}
}
public interface KeySourceGetter {
Object getValue(K key, S source) throws SQLException;
}
private static class MappingContextFactoryImpl implements MappingContextFactory {
private final BreakDetector[] breakDetectors;
private final BreakDetector rootDetector;
public MappingContextFactoryImpl(BreakDetector[] breakDetectors, BreakDetector rootDetector) {
this.breakDetectors = breakDetectors;
this.rootDetector = rootDetector;
}
@Override
public MappingContext newContext() {
return new MappingContext(breakDetectors, rootDetector);
}
}
private static class BreakDetectorImpl implements BreakDetector {
private final KeySourceGetter keySourceGetter;
private final List keys;
private final BreakDetector parent;
private Object[] lastValues;
private boolean isBroken = true;
public BreakDetectorImpl(List keys, KeySourceGetter keySourceGetter, BreakDetector parent) {
this.keys = keys;
this.keySourceGetter = keySourceGetter;
this.parent = parent;
}
@Override
public void handle(S source) throws MappingException {
if (keys.isEmpty()) {
return;
}
Object[] newValues = getValues(source);
isBroken = (parent != null && parent.isBroken())
|| lastValues == null
|| !Arrays.equals(lastValues, newValues);
lastValues = newValues;
}
private Object[] getValues(S source) {
try {
Object[] values = new Object[keys.size()];
for (int i = 0; i < values.length; i++) {
values[i] = keySourceGetter.getValue(keys.get(i), source);
}
return values;
} catch (Exception e) {
return ErrorHelper.rethrow(e);
}
}
@Override
public boolean isBroken() {
return isBroken;
}
@Override
public void markAsBroken() {
isBroken = true;
lastValues = null;
}
}
@Override
public String toString() {
return "MappingContextFactoryBuilder{" +
"currentIndex=" + currentIndex +
", keys=" + keys +
", children=" + children +
'}';
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy