org.sfm.jdbc.impl.DiscriminatorJdbcMapper Maven / Gradle / Ivy
package org.sfm.jdbc.impl;
import org.sfm.map.*;
import org.sfm.tuples.Tuple2;
import org.sfm.utils.*;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
public final class DiscriminatorJdbcMapper extends AbstractForEachDynamicJdbcMapper {
private final String discriminatorColumn;
private final List, Mapper>> mappers;
public DiscriminatorJdbcMapper(String discriminatorColumn, List, Mapper>> mappers, RowHandlerErrorHandler rowHandlerErrorHandler) {
super(rowHandlerErrorHandler);
this.discriminatorColumn = discriminatorColumn;
this.mappers = mappers;
}
@Override
public MappingContext newMappingContext(ResultSet source) throws MappingException {
try {
return getMapper(source).newMappingContext(source);
} catch (SQLException e) {
return ErrorHelper.rethrow(e);
}
}
private MappingContext[] getMappingContexts(ResultSet rs) throws SQLException {
@SuppressWarnings("unchecked")
MappingContext[] mappingContexts = new MappingContext[mappers.size()];
int i = 0;
for(Tuple2, Mapper> tm : mappers) {
mappingContexts[i] = tm.getElement1().newMappingContext(rs);
i++;
}
return mappingContexts;
}
private Mapper getMapper(int index) {
return mappers.get(index).getElement1();
}
protected Mapper getMapper(final ResultSet rs) throws MappingException, SQLException {
String value = rs.getString(discriminatorColumn);
for(Tuple2, Mapper> tm : mappers) {
if (tm.first().test(value)) {
return tm.second();
}
}
throw new MappingException("No mapper found for " + discriminatorColumn + " = " + value);
}
private int getMapperIndex(final ResultSet rs) throws MappingException, SQLException {
String value = rs.getString(discriminatorColumn);
int i = 0;
for(Tuple2, Mapper> tm : mappers) {
if (tm.first().test(value)) {
return i;
}
i++;
}
throw new MappingException("No mapper found for " + discriminatorColumn + " = " + value);
}
protected DiscriminatorForEach newForEachIterator(ResultSet rs) throws SQLException {
return new DiscriminatorForEach(this, getMappingContexts(rs), errorHandler, rs);
}
@Override
public String toString() {
return "DiscriminatorJdbcMapper{" +
"discriminatorColumn='" + discriminatorColumn + '\'' +
", mappers=" + mappers +
'}';
}
private static class DiscriminatorForEach implements ForEachIterator {
private final DiscriminatorJdbcMapper mapper;
private final MappingContext[] mappingContexts;
private final RowHandlerErrorHandler rowHandlerErrorHandler;
private final ResultSet resultSet;
private int currentMapperIndex = -1;
private T currentValue;
private Mapper currentMapper;
private MappingContext currentMappingContext;
public DiscriminatorForEach(DiscriminatorJdbcMapper mapper,
MappingContext[] mappingContexts,
RowHandlerErrorHandler rowHandlerErrorHandler, ResultSet resultSet) {
this.mapper = mapper;
this.mappingContexts = mappingContexts;
this.rowHandlerErrorHandler = rowHandlerErrorHandler;
this.resultSet = resultSet;
}
@Override
public boolean next(RowHandler rowHandler) throws Exception {
return forEach(true, rowHandler);
}
@Override
public void forEach(RowHandler rowHandler) throws Exception {
forEach(false, rowHandler);
}
private boolean forEach(boolean stopOnNext, RowHandler rowHandler) throws Exception {
while (resultSet.next()) {
checkMapper();
currentMappingContext.handle(resultSet);
if (currentMappingContext.rootBroke()) {
if (currentValue != null) {
callHandler(rowHandler);
currentValue = currentMapper.map(resultSet, currentMappingContext);
if (stopOnNext) {
return true;
}
} else {
currentValue = currentMapper.map(resultSet, currentMappingContext);
}
} else {
currentMapper.mapTo(resultSet, currentValue, currentMappingContext);
}
}
if (currentValue != null) {
callHandler(rowHandler);
currentValue = null;
return true;
} else {
return false;
}
}
private void callHandler(RowHandler rowHandler) throws Exception {
try {
rowHandler.handle(currentValue);
} catch(Exception e) {
rowHandlerErrorHandler.handlerError(e, currentValue);
}
}
private void checkMapper() throws java.sql.SQLException {
int mapperIndex = mapper.getMapperIndex(resultSet);
if (currentMapperIndex != mapperIndex) {
mapperChange(mapperIndex);
}
}
private void mapperChange(int newMapperIndex) {
markAsBroken(mappingContexts);
currentMapper = this.mapper.getMapper(newMapperIndex);
currentMappingContext = mappingContexts[newMapperIndex];
currentMapperIndex = newMapperIndex;
}
private void markAsBroken(MappingContext[] mappingContexts) {
for(int i = 0; i < mappingContexts.length; i++) {
mappingContexts[i].markAsBroken();
}
}
}
}