package org.openlca.util; import java.util.HashMap; import java.util.function.Consumer; import javax.persistence.Table; import org.apache.commons.math3.util.Pair; import org.openlca.core.database.IDatabase; import org.openlca.core.database.NativeSql; import org.openlca.core.model.RootEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * In the imports and exports we often need a mapping of reference IDs to * database internal IDs or the other way around. This class exactly provides * such mappings by caching all IDs from the database. */ public class RefIdMap<From, To> { private final HashMap<Class<?>, HashMap<From, To>> map = new HashMap<>(); @SafeVarargs public static <T extends RootEntity> RefIdMap<Long, String> internalToRef( IDatabase db, Class<? extends T>... types) { RefIdMap<Long, String> refMap = new RefIdMap<>(); for (Class<?> type : types) { HashMap<Long, String> map = new HashMap<>(); refMap.map.put(type, map); scan(db, type, p -> { map.put(p.getFirst(), p.getSecond()); }); } return refMap; } @SafeVarargs public static <T extends RootEntity> RefIdMap<String, Long> refToInternal( IDatabase db, Class<? extends T>... types) { RefIdMap<String, Long> refMap = new RefIdMap<>(); for (Class<?> type : types) { HashMap<String, Long> map = new HashMap<>(); refMap.map.put(type, map); scan(db, type, p -> { map.put(p.getSecond(), p.getFirst()); }); } return refMap; } private static void scan(IDatabase db, Class<?> type, Consumer<Pair<Long, String>> fn) { String table = getTable(type); if (table == null) return; String sql = "select id, ref_id from " + table; try { NativeSql.on(db).query(sql, r -> { long id = r.getLong(1); String refId = r.getString(2); fn.accept(new Pair<Long, String>(id, refId)); return true; }); } catch (Exception e) { Logger log = LoggerFactory.getLogger(RefIdMap.class); log.error("failed to get database table", e); } } private static String getTable(Class<?> type) { try { Table table = type.getAnnotation(Table.class); return table.name(); } catch (Exception e) { Logger log = LoggerFactory.getLogger(RefIdMap.class); log.error("failed to get database table", e); return null; } } public To get(Class<?> type, From id) { if (type == null || id == null) return null; HashMap<From, To> m = map.get(type); return m == null ? null : m.get(id); } }