Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.carml.engine.RmlMapper Maven / Gradle / Ivy
package io.carml.engine;
import static io.carml.util.LogUtil.exception;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toSet;
import com.google.common.collect.Iterables;
import io.carml.logicalsourceresolver.LogicalSourceRecord;
import io.carml.logicalsourceresolver.LogicalSourceResolver;
import io.carml.logicalsourceresolver.ResolvedSource;
import io.carml.model.LogicalSource;
import io.carml.model.NameableStream;
import io.carml.model.TriplesMap;
import io.carml.util.Mappings;
import java.io.InputStream;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import reactor.core.publisher.Flux;
@Slf4j
@AllArgsConstructor
public abstract class RmlMapper {
public static final String DEFAULT_STREAM_NAME = "DEFAULT";
@Getter
private Set triplesMaps;
private Function> sourceResolver;
private Set> triplesMappers;
private Map, TriplesMapper> refObjectMapperToParentTriplesMapper;
private Map> sourceToLogicalSourceResolver;
public Flux mapRecord(R providedRecord, Class providedRecordClass) {
return mapRecord(providedRecord, providedRecordClass, Set.of());
}
public Flux mapRecord(R providedRecord, Class providedRecordClass, Set triplesMapFilter) {
return map(null, providedRecord, providedRecordClass, triplesMapFilter);
}
public Flux map() {
return map(Map.of());
}
public Flux map(Set triplesMapFilter) {
return map(Map.of(), triplesMapFilter);
}
public Flux map(@NonNull InputStream inputStream) {
return map(Map.of(DEFAULT_STREAM_NAME, inputStream));
}
public Flux map(@NonNull InputStream inputStream, Set triplesMapFilter) {
return map(Map.of(DEFAULT_STREAM_NAME, inputStream), triplesMapFilter);
}
public Flux map(Map namedInputStreams) {
return map(namedInputStreams, Set.of());
}
public Flux map(Map namedInputStreams, Set triplesMapFilter) {
return map(namedInputStreams, null, null, triplesMapFilter);
}
private Flux map(Map namedInputStreams, V providedRecord, Class providedRecordClass,
Set triplesMapFilter) {
var mappingContext = MappingContext.builder()
.triplesMapFilter(triplesMapFilter)
.triplesMappers(triplesMappers)
.refObjectMapperToParentTriplesMapper(refObjectMapperToParentTriplesMapper)
.build();
return Flux.fromIterable(getSources(mappingContext, namedInputStreams, providedRecord, providedRecordClass))
.flatMap(resolvedSourceEntry -> mapSource(mappingContext, resolvedSourceEntry))
.concatWith(resolveJoins(mappingContext))
.doOnTerminate(() -> triplesMappers.forEach(TriplesMapper::cleanup));
}
private Set> getSources(MappingContext mappingContext,
Map namedInputStreams, V providedRecord, Class providedRecordClass) {
var logicalSourcesPerSource = mappingContext.getLogicalSourcesPerSource();
if (providedRecord != null) {
if (logicalSourcesPerSource.size() > 1) {
throw new RmlMapperException(
String.format("Multiple sources found when mapping provided record. This is not supported:%n%s",
exception(logicalSourcesPerSource.values()
.stream()
.flatMap(Set::stream)
.collect(toSet()))));
}
return Set.of(ResolvedSource.of(Iterables.getFirst(logicalSourcesPerSource.keySet(), null), providedRecord,
providedRecordClass));
}
return logicalSourcesPerSource.entrySet()
.stream()
.map(sourceEntry -> resolveSource(sourceEntry.getKey(), sourceEntry.getValue(), namedInputStreams))
.collect(Collectors.toUnmodifiableSet());
}
private ResolvedSource> resolveSource(Object source, Set inCaseOfException,
Map namedInputStreams) {
if (source instanceof NameableStream) {
NameableStream stream = (NameableStream) source;
String unresolvedName = stream.getStreamName();
String name = StringUtils.isBlank(unresolvedName) ? DEFAULT_STREAM_NAME : unresolvedName;
if (!namedInputStreams.containsKey(name)) {
throw new RmlMapperException(String.format("Could not resolve input stream with name %s for logical source: %s",
name, exception(Iterables.getFirst(inCaseOfException, null))));
}
return ResolvedSource.of(source, namedInputStreams.get(name), InputStream.class);
}
var resolved = sourceResolver.apply(source)
.orElseThrow(() -> new RmlMapperException(String.format("Could not resolve source for logical source: %s",
exception(Iterables.getFirst(inCaseOfException, null)))));
return ResolvedSource.of(source, resolved, Object.class);
}
private Flux mapSource(MappingContext mappingContext, ResolvedSource> resolvedSource) {
return Flux.just(sourceToLogicalSourceResolver.get(resolvedSource.getRmlSource()))
.flatMap(resolver -> resolver
.getLogicalSourceRecords(mappingContext.logicalSourcesPerSource.get(resolvedSource.getRmlSource()))
.apply(resolvedSource))
.flatMap(logicalSourceRecord -> mapTriples(mappingContext, logicalSourceRecord));
}
private Flux mapTriples(MappingContext mappingContext, LogicalSourceRecord> logicalSourceRecord) {
return Flux.fromIterable(mappingContext.getTriplesMappersForLogicalSource(logicalSourceRecord.getLogicalSource()))
.flatMap(triplesMapper -> triplesMapper.map(logicalSourceRecord));
}
private Flux resolveJoins(MappingContext mappingContext) {
return Flux.fromIterable(mappingContext.getRefObjectMapperToParentTriplesMapper()
.entrySet())
.flatMap(romMapperPtMapper -> romMapperPtMapper.getKey()
.resolveJoins(romMapperPtMapper.getValue()));
}
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
static class MappingContext {
private Set triplesMapFilter;
private Map>> triplesMapperPerLogicalSource;
private Map> logicalSourcesPerSource;
private Map, TriplesMapper> refObjectMapperToParentTriplesMapper;
public Set> getTriplesMappersForLogicalSource(LogicalSource logicalSource) {
return triplesMapperPerLogicalSource.get(logicalSource);
}
static MappingContext.Builder builder() {
return new MappingContext.Builder<>();
}
@NoArgsConstructor(access = AccessLevel.PRIVATE)
static class Builder {
private Set triplesMapFilter;
private Set> triplesMappers;
private Map, TriplesMapper> refObjectMapperToParentTriplesMapper;
public MappingContext.Builder triplesMapFilter(Set triplesMapFilter) {
this.triplesMapFilter = triplesMapFilter;
return this;
}
public MappingContext.Builder triplesMappers(Set> triplesMappers) {
this.triplesMappers = triplesMappers;
return this;
}
public MappingContext.Builder refObjectMapperToParentTriplesMapper(
Map, TriplesMapper> refObjectMapperToParentTriplesMapper) {
this.refObjectMapperToParentTriplesMapper = refObjectMapperToParentTriplesMapper;
return this;
}
public MappingContext build() {
var actionableTriplesMaps = Mappings.filterMappable(triplesMappers.stream()
.map(TriplesMapper::getTriplesMap)
.filter(triplesMap -> triplesMapFilter.isEmpty() || triplesMapFilter.contains(triplesMap))
.collect(toSet()));
var filteredTriplesMappersPerLogicalSource = triplesMappers.stream()
.filter(triplesMapper -> actionableTriplesMaps.contains(triplesMapper.getTriplesMap()))
.collect(groupingBy(triplesMapper -> triplesMapper.getTriplesMap()
.getLogicalSource(), toSet()));
var filteredLogicalSourcesPerSource = filteredTriplesMappersPerLogicalSource.keySet()
.stream()
.collect(groupingBy(LogicalSource::getSource, toSet()));
Map, TriplesMapper> filteredRefObjectMapperToParentTriplesMapper =
refObjectMapperToParentTriplesMapper.entrySet()
.stream()
.filter(entry -> actionableTriplesMaps.contains(entry.getKey()
.getTriplesMap()))
.collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue));
return new MappingContext<>(actionableTriplesMaps, filteredTriplesMappersPerLogicalSource,
filteredLogicalSourcesPerSource, filteredRefObjectMapperToParentTriplesMapper);
}
}
}
}