package org.openlca.io.ecospold1.input; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import org.apache.commons.lang3.StringUtils; import org.openlca.core.database.IDatabase; import org.openlca.core.database.Query; import org.openlca.core.model.Actor; import org.openlca.core.model.Category; import org.openlca.core.model.Flow; import org.openlca.core.model.FlowType; import org.openlca.core.model.Location; import org.openlca.core.model.Source; import org.openlca.ecospold.IExchange; import org.openlca.ecospold.IPerson; import org.openlca.ecospold.IReferenceFunction; import org.openlca.ecospold.ISource; import org.openlca.ecospold.io.DataSet; import org.openlca.io.UnitMappingEntry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Strings; /** Search for EcoSpold entities in the database. */ class DBSearch { private IDatabase database; private Logger log = LoggerFactory.getLogger(getClass()); public DBSearch(IDatabase database) { this.database = database; } public Actor findActor(IPerson person) { try { log.trace("Search for actor {} in database", person.getName()); String jpql = "select a from Actor a where a.name = :name " + "and a.address = :address"; Map<String, Object> args = new HashMap<>(); args.put("name", person.getName()); args.put("address", person.getAddress()); return Query.on(database).getFirst(Actor.class, jpql, args); } catch (Exception e) { log.error("Failed to search for Actor", e); return null; } } public Source findSource(ISource source) { try { log.trace("Search for source {} in database", source.getTitle()); String jpql = "select s from Source s where s.name = :name"; Map<String, Object> args = new HashMap<>(); int year = source.getYear() != null ? source.getYear().getYear() : 0; args.put("name", source.getFirstAuthor() + " " + year); Source candidate = Query.on(database).getFirst(Source.class, jpql, args); if (candidate == null) return null; if (Objects.equals(candidate.getTextReference(), source.getTitle())) return candidate; return null; } catch (Exception e) { log.error("Failed to search for Source", e); return null; } } public Location findLocation(String locationCode) { try { log.trace("Search for location {} in database", locationCode); String jpql = "select loc from Location loc " + "where loc.code = :locationCode"; return Query.on(database).getFirst(Location.class, jpql, Collections.singletonMap("locationCode", locationCode)); } catch (Exception e) { log.error("Failed to search for Location", e); return null; } } public Flow findFlow(IExchange exchange, UnitMappingEntry mapping) { List<Flow> candidates = findFlows(exchange.getName()); if (candidates == null || candidates.isEmpty()) return null; for (Flow flow : candidates) { if (!sameFlowType(exchange, flow)) continue; if (!hasUnit(flow, mapping)) continue; if (!sameCategory(exchange.getCategory(), exchange.getSubCategory(), flow)) continue; if (!sameLocation(exchange.getLocation(), flow)) continue; return flow; } return null; } public Flow findFlow(DataSet dataSet, UnitMappingEntry mapping) { IReferenceFunction refFun = dataSet.getReferenceFunction(); if (refFun == null) return null; List<Flow> candidates = findFlows(refFun.getName()); if (candidates == null || candidates.isEmpty()) return null; for (Flow flow : candidates) { if (!hasUnit(flow, mapping)) continue; if (!sameCategory(refFun.getCategory(), refFun.getSubCategory(), flow)) continue; String locationCode = dataSet.getGeography() == null ? null : dataSet.getGeography().getLocation(); if (!sameLocation(locationCode, flow)) continue; return flow; } return null; } private List<Flow> findFlows(String name) { try { log.trace("Search for flow {} in database", name); String jpql = "select f from Flow f where f.name = :name"; return Query.on(database).getAll(Flow.class, jpql, Collections.singletonMap("name", name)); } catch (Exception e) { log.error("Flow search failed", e); return Collections.emptyList(); } } private boolean sameFlowType(IExchange exchange, Flow flow) { if (exchange.isElementaryFlow()) return flow.getFlowType() == FlowType.ELEMENTARY_FLOW; return flow.getFlowType() != FlowType.ELEMENTARY_FLOW; } private boolean hasUnit(Flow flow, UnitMappingEntry mapping) { if (flow == null || mapping == null || mapping.flowProperty == null) return false; return flow.getFactor(mapping.flowProperty) != null; } private boolean sameCategory(String categoryName, String subCategoryName, Flow flow) { try { Category category = flow.getCategory(); if (category == null) return Strings.isNullOrEmpty(categoryName) && Strings.isNullOrEmpty(subCategoryName); Category parent = category.getCategory(); if (parent == null) return sameCategory(categoryName, category) || sameCategory(subCategoryName, category); else return sameCategory(subCategoryName, category) && sameCategory(categoryName, parent); } catch (Exception e) { log.error("Failed to check categories"); return false; } } private boolean sameCategory(String name, Category category) { if (Strings.isNullOrEmpty(name) && category == null) return true; if (Strings.isNullOrEmpty(name) || category == null) return false; return StringUtils.equalsIgnoreCase(name, category.getName()); } private boolean sameLocation(String locationCode, Flow flow) { if (locationCode == null || locationCode.equals("GLO")) return flow.getLocation() == null || "GLO".equalsIgnoreCase(flow.getLocation().getCode()); if (flow.getLocation() == null) return false; return StringUtils.equalsIgnoreCase(locationCode, flow.getLocation() .getCode()); } }