package nl.fontys.sofa.limo.externaltrader; import nl.fontys.sofa.limo.domain.component.MasterData; import com.google.gson.Gson; import com.google.gson.stream.JsonReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import nl.fontys.sofa.limo.api.dao.DAO; import nl.fontys.sofa.limo.api.service.provider.EventService; import nl.fontys.sofa.limo.api.service.provider.HubService; import nl.fontys.sofa.limo.api.service.provider.HubTypeService; import nl.fontys.sofa.limo.api.service.provider.LegTypeService; import nl.fontys.sofa.limo.api.service.provider.ProcedureCategoryService; import nl.fontys.sofa.limo.api.service.provider.ProcedureService; import nl.fontys.sofa.limo.domain.BaseEntity; import nl.fontys.sofa.limo.domain.component.serialization.GsonHelper; import org.openide.util.Lookup; /** * @author Matthias Brück * @author Dominik Kaisers */ public final class JSONImporter { /** * Number of entities found in the last JSON file. */ private static int lastEntitiesInFileCount; /** * Number of directly imported files from the last JSON file. */ private static int lastDirectImportedEntityCount; /** * Number of duplicated elements in the last JSON file. Duplicated means * that there is already an entity inside the database that has the same * unique identifier. */ private static int lastDuplicatedEntityCount; /** * Number of entities in JSON file that are from an older date then the ones * in the database. */ private static int lastOlderEntityCount; private JSONImporter() { } /** * Import database entities from a serialized .lef file. * * @param filepath Filepath where the lef file can be loaded from * @return Map with entities that have a conflict with the local database. */ public static Map<String, List<Map.Entry<BaseEntity, BaseEntity>>> importData(String filepath) { lastEntitiesInFileCount = 0; lastDirectImportedEntityCount = 0; lastDuplicatedEntityCount = 0; lastOlderEntityCount = 0; Map<String, List<BaseEntity>> allEntities = (Map<String, List<BaseEntity>>) loadFromFile(filepath); Map<String, List<BaseEntity>> checkedEntities = new HashMap<>(allEntities); Set<String> keys = allEntities.keySet(); keys.stream().forEach((next) -> { List<BaseEntity> baseList = allEntities.get(next); if (baseList == null) { checkedEntities.remove(next); } }); return checkForConflicts(checkedEntities); } /** * Load a .lef file form a filepath. * * @param filepath Filepath. * @return Deserialized entities. */ private static Object loadFromFile(String filepath) { try { InputStream in = new FileInputStream(filepath); Gson g = GsonHelper.getInstance(); MasterData md; try (JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"))) { reader.beginArray(); md = g.fromJson(reader, MasterData.class); reader.endArray(); } return md.getAsMap(); } catch (FileNotFoundException | UnsupportedEncodingException ex) { ex.printStackTrace(System.err); } catch (IOException ex) { ex.printStackTrace(System.err); } return null; } /** * Check all the entities in the map for conflicts with the local database. * * @param allEntities Entity map. * @return Conflict map. */ private static Map<String, List<Map.Entry<BaseEntity, BaseEntity>>> checkForConflicts(Map<String, List<BaseEntity>> allEntities) { Map<String, List<Map.Entry<BaseEntity, BaseEntity>>> conflictMap = new HashMap<>(); allEntities.entrySet().stream().forEach((entry) -> { conflictMap.put(entry.getKey(), checkItems(entry.getValue(), getServiceClassForKey(entry.getKey()))); }); return conflictMap; } /** * Get the dao class for a key. * * @param key Key. * @return DAO class. */ private static Class getServiceClassForKey(String key) { switch (key) { case "categories": return ProcedureCategoryService.class; case "legtypes": return LegTypeService.class; case "hubtypes": return HubTypeService.class; case "hubs": return HubService.class; case "events": return EventService.class; case "basicProcedures": return ProcedureService.class; default: return null; } } /** * Check each item in the list for conflicts. * * @param entities Items to check. * @param daoClass Associated DAO class. * @return List of conflicted items. */ private static List<Map.Entry<BaseEntity, BaseEntity>> checkItems(List<BaseEntity> entities, Class serviceClass) { List<Map.Entry<BaseEntity, BaseEntity>> list = new ArrayList<>(); entities.stream().map((entity) -> checkItem(entity, serviceClass)).filter((item) -> (item != null)).forEach((item) -> { list.add(item); }); return list; } /** * Checks a given base entity for conflicts and duplications in the * database. * * @param newItem Item to check. * @param daoClass Associated DAO class. * @return Map.Entry with old and new base entity or null if no * conflict/duplication found. */ private static Map.Entry<BaseEntity, BaseEntity> checkItem(BaseEntity newItem, Class serviceClass) { lastEntitiesInFileCount++; DAO dao = (DAO) Lookup.getDefault().lookup(serviceClass); BaseEntity oldItem = dao.findByUniqueIdentifier(newItem.getUniqueIdentifier()); Map.Entry<BaseEntity, BaseEntity> entry = null; if (oldItem != null) { if (oldItem.getLastUpdate() != newItem.getLastUpdate()) { entry = new AbstractMap.SimpleEntry<>(oldItem, newItem); lastDuplicatedEntityCount++; } else { lastOlderEntityCount++; } } else { dao.insert(newItem, false); lastDirectImportedEntityCount++; } return entry; } public static int getLastEntitiesInFileCount() { return lastEntitiesInFileCount; } public static int getLastDirectImportedEntityCount() { return lastDirectImportedEntityCount; } public static int getLastDuplicatedEntityCount() { return lastDuplicatedEntityCount; } public static int getLastOlderEntityCount() { return lastOlderEntityCount; } }