package org.openlca.core.matrix.cache; import java.sql.Connection; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; import java.util.Objects; import org.openlca.core.database.IDatabase; import org.openlca.core.database.NativeSql; import org.openlca.core.matrix.LongPair; import org.openlca.core.model.AllocationMethod; import org.openlca.core.model.FlowType; import org.openlca.core.model.ProcessType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import gnu.trove.iterator.TLongObjectIterator; import gnu.trove.list.array.TLongArrayList; import gnu.trove.map.hash.TLongObjectHashMap; public class ProcessTable { private Logger log = LoggerFactory.getLogger(getClass()); private final TLongObjectHashMap<ProcessType> typeMap = new TLongObjectHashMap<>(); private final TLongObjectHashMap<AllocationMethod> allocMap = new TLongObjectHashMap<>(); /** * Maps IDs of product flows to process IDs that have this product as * output: product-id -> provider-process-id. We need this when we build a * product system automatically. */ private final TLongObjectHashMap<TLongArrayList> productMap = new TLongObjectHashMap<>(); public static ProcessTable create(IDatabase db, FlowTypeTable flowTypes) { ProcessTable table = new ProcessTable(db, flowTypes); return table; } private ProcessTable(IDatabase db, FlowTypeTable flowTypes) { log.trace("build process index table"); initTypeAndAllocation(db); initProductMap(db, flowTypes); } private void initProductMap(IDatabase db, FlowTypeTable flowTypes) { log.trace("load product->process map"); String query = "select f_owner, f_flow from tbl_exchanges" + " where is_input = 0"; try { NativeSql.on(db).query(query, r -> { long processId = r.getLong(1); long flowId = r.getLong(2); if (flowTypes.get(flowId) == FlowType.PRODUCT_FLOW) indexProvider(flowId, processId); return true; }); log.trace("{} products mapped", productMap.size()); } catch (Exception e) { log.error("failed to load process products", e); } } private void indexProvider(long productId, long processId) { TLongArrayList list = productMap.get(productId); if (list == null) { list = new TLongArrayList(); productMap.put(productId, list); } list.add(processId); } private void initTypeAndAllocation(IDatabase database) { log.trace("index process and allocation types"); try (Connection con = database.createConnection()) { String query = "select id, process_type, default_allocation_method " + "from tbl_processes"; ResultSet result = con.createStatement().executeQuery(query); while (result.next()) fetchValues(result); result.close(); log.trace("{} processes indexed", typeMap.size()); } catch (Exception e) { log.error("failed to build process type index", e); } } private void fetchValues(ResultSet result) throws Exception { long id = result.getLong("id"); String typeString = result.getString("process_type"); ProcessType type = Objects.equals(ProcessType.LCI_RESULT.name(), typeString) ? ProcessType.LCI_RESULT : ProcessType.UNIT_PROCESS; typeMap.put(id, type); String allocString = result.getString("default_allocation_method"); if (allocString != null) { AllocationMethod m = AllocationMethod.valueOf(allocString); allocMap.put(id, m); } } /** Returns the process type for the given process-ID. */ public ProcessType getType(long processId) { return typeMap.get(processId); } /** Note that this method can return <code>null</code> */ public AllocationMethod getDefaultAllocationMethod(long processId) { return allocMap.get(processId); } /** * Returns the list of process IDs that have the product flow with the given * ID as output. */ public long[] getProductProviders(long productId) { TLongArrayList list = productMap.get(productId); if (list == null) return new long[0]; return list.toArray(); } /** Gets all process products of the database. */ public List<LongPair> getProcessProducts() { List<LongPair> list = new ArrayList<>(); TLongObjectIterator<TLongArrayList> it = productMap.iterator(); while (it.hasNext()) { it.advance(); long productId = it.key(); for (long processId : it.value().toArray()) { list.add(LongPair.of(processId, productId)); } } return list; } }