org.openlca.proto.io.server.FlowMapService Maven / Gradle / Ivy
package org.openlca.proto.io.server;
import org.openlca.core.database.IDatabase;
import org.openlca.core.database.MappingFileDao;
import org.openlca.core.model.MappingFile;
import org.openlca.core.model.descriptors.FlowDescriptor;
import org.openlca.core.model.descriptors.ProcessDescriptor;
import org.openlca.core.io.maps.FlowMap;
import org.openlca.core.io.maps.FlowMapEntry;
import org.openlca.core.io.maps.FlowRef;
import org.openlca.proto.ProtoFlowMap;
import org.openlca.proto.ProtoFlowMapEntry;
import org.openlca.proto.ProtoFlowMapRef;
import org.openlca.proto.grpc.FlowMapServiceGrpc;
import org.openlca.proto.grpc.ProtoFlowMapName;
import org.openlca.proto.io.Messages;
import org.openlca.proto.io.input.In;
import org.openlca.proto.io.output.Refs;
import org.openlca.util.Strings;
import com.google.protobuf.Empty;
import io.grpc.stub.StreamObserver;
class FlowMapService extends FlowMapServiceGrpc.FlowMapServiceImplBase {
private final IDatabase db;
FlowMapService(IDatabase db) {
this.db = db;
}
@Override
public void getAll(Empty req, StreamObserver resp) {
new MappingFileDao(db).getNames()
.stream()
.sorted(Strings::compare)
.map(name -> ProtoFlowMapName.newBuilder().setName(name).build())
.forEach(resp::onNext);
resp.onCompleted();
}
@Override
public void get(ProtoFlowMapName req, StreamObserver resp) {
var mapping = forceGet(req.getName(), resp);
if (mapping == null)
return;
var flowMap = FlowMap.of(mapping);
resp.onNext(toProto(flowMap));
resp.onCompleted();
}
@Override
public void delete(ProtoFlowMapName req, StreamObserver resp) {
var mapping = forceGet(req.getName(), resp);
if (mapping == null)
return;
try {
new MappingFileDao(db).delete(mapping);
Response.ok(resp);
} catch (Exception e) {
Response.serverError(resp,
"Failed to delete mapping with name='"
+ req.getName() + "' from database");
}
}
private MappingFile forceGet(String name, StreamObserver> resp) {
if (Strings.nullOrEmpty(name)) {
Response.invalidArg(resp,
"No name of the flow map was given.");
return null;
}
var mapping = findByName(name);
if (mapping == null) {
Response.notFound(resp,
"Could not load flow map '" + name + "'");
}
return mapping;
}
private MappingFile findByName(String name) {
var dao = new MappingFileDao(db);
var existing = dao.getNames()
.stream()
.filter(name::equalsIgnoreCase)
.findAny()
.orElse(null);
if (existing == null)
return null;
return dao.getForName(existing);
}
@Override
public void put(ProtoFlowMap proto, StreamObserver resp) {
var model = toModel(proto);
if (Strings.nullOrEmpty(model.name)) {
Response.invalidArg(resp, "A name of the flow map is required");
return;
}
var dao = new MappingFileDao(db);
// check if we should update an existing map
var mapping = findByName(model.name);
if (mapping != null) {
try {
model.updateContentOf(mapping);
dao.update(mapping);
Response.ok(resp);
} catch (Exception e) {
Response.serverError(resp,
"Failed to update existing" +
" flow map " + model.name + ": " + e.getMessage());
}
return;
}
// save it as new flow map
mapping = model.toMappingFile();
try {
dao.insert(mapping);
Response.ok(resp);
} catch (Exception e) {
Response.serverError(resp,
"Failed to save mapping "
+ model.name + ": " + e.getMessage());
}
}
private FlowMap toModel(ProtoFlowMap proto) {
if (proto == null)
return FlowMap.empty();
var flowMap = new FlowMap();
flowMap.name = proto.getName();
flowMap.refId = proto.getId();
for (var protoEntry : proto.getMappingsList()) {
var source = toModelRef(protoEntry.getFrom());
var target = toModelRef(protoEntry.getTo());
var factor = protoEntry.getConversionFactor();
flowMap.entries.add(new FlowMapEntry(source, target, factor));
}
return flowMap;
}
private FlowRef toModelRef(ProtoFlowMapRef protoRef) {
var flowRef = new FlowRef();
if (Messages.isEmpty(protoRef))
return flowRef;
// flow information
flowRef.flow = In.fill(new FlowDescriptor(), protoRef.getFlow());
// TODO: set category path
// flowRef.flowCategory = categoryPathOf(
// protoRef.getFlow().getCategoryPathList());
flowRef.flowLocation = Strings.nullIfEmpty(
protoRef.getFlow().getLocation());
// flow property
var property = protoRef.getFlowProperty();
if (Messages.isNotEmpty(property)) {
flowRef.property = In.descriptorOf(property);
}
// unit
var unit = protoRef.getUnit();
if (Messages.isNotEmpty(unit)) {
flowRef.unit = In.descriptorOf(unit);
}
// provider
var provider = protoRef.getProvider();
if (Messages.isNotEmpty(provider)) {
flowRef.provider = In.fill(
new ProcessDescriptor(), provider);
flowRef.providerCategory = provider.getCategory();
flowRef.providerLocation = Strings.nullIfEmpty(
provider.getLocation());
}
return flowRef;
}
private ProtoFlowMap toProto(FlowMap model) {
var proto = ProtoFlowMap.newBuilder();
if (model == null)
return proto.build();
proto.setId(Strings.orEmpty(model.refId));
proto.setName(Strings.orEmpty(model.name));
proto.setDescription(Strings.orEmpty(model.name));
for (var entry : model.entries) {
var protoEntry = ProtoFlowMapEntry.newBuilder();
protoEntry.setConversionFactor(entry.factor());
if (entry.sourceFlow() != null) {
protoEntry.setFrom(toProtoRef(entry.sourceFlow()));
}
if (entry.targetFlow() != null) {
protoEntry.setTo(toProtoRef(entry.targetFlow()));
}
proto.addMappings(protoEntry);
}
return proto.build();
}
private ProtoFlowMapRef toProtoRef(FlowRef flowRef) {
var proto = ProtoFlowMapRef.newBuilder();
if (flowRef == null || flowRef.flow == null)
return proto.build();
// flow
var protoFlow = Refs.refOf(flowRef.flow);
if (flowRef.flowCategory != null) {
protoFlow.setCategory(flowRef.flowCategory);
}
if (flowRef.flowLocation != null) {
protoFlow.setLocation(flowRef.flowLocation);
}
proto.setFlow(protoFlow);
// flow property & unit
if (flowRef.property != null) {
proto.setFlowProperty(Refs.refOf(flowRef.property));
}
if (flowRef.unit != null) {
proto.setUnit(Refs.refOf(flowRef.unit));
}
// provider
if (flowRef.provider != null) {
var protoProv = Refs.refOf(flowRef.provider);
if (flowRef.providerLocation != null) {
protoProv.setLocation(flowRef.providerLocation);
}
if (flowRef.providerCategory != null) {
protoProv.setCategory(flowRef.providerCategory);
}
proto.setProvider(protoProv);
}
return proto.build();
}
}