From 3488a3e7bc4dcca8db70dc16728a9f8822fe054f Mon Sep 17 00:00:00 2001 From: shraddha singh Date: Wed, 21 Aug 2024 17:02:43 +0530 Subject: [PATCH 1/8] #754 | Implementer friendliness for avni --- .../server/service/MetadataDiffService.java | 370 ++++++++++++++++++ .../server/web/MetadataDiffController.java | 32 ++ ...MetadataDiffControllerIntegrationTest.java | 25 ++ 3 files changed, 427 insertions(+) create mode 100644 avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java create mode 100644 avni-server-api/src/main/java/org/avni/server/web/MetadataDiffController.java create mode 100644 avni-server-api/src/test/java/org/avni/server/web/MetadataDiffControllerIntegrationTest.java diff --git a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java new file mode 100644 index 000000000..9d8fb0aa0 --- /dev/null +++ b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java @@ -0,0 +1,370 @@ +package org.avni.server.service; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.type.TypeReference; + +import java.io.*; +import java.nio.file.Files; +import java.util.*; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +@Service +public class MetadataDiffService { + + private static final Logger logger = LoggerFactory.getLogger(MetadataDiffService.class); + private static final ObjectMapper objectMapper = new ObjectMapper(); + + public Map compareMetadataZips(MultipartFile zipFile1, MultipartFile zipFile2) throws IOException { + Map result = new HashMap<>(); + File tempDir1 = null, tempDir2 = null; + + try { + tempDir1 = extractZip(zipFile1); + tempDir2 = extractZip(zipFile2); + + List files1 = listJsonFiles(tempDir1); + List files2 = listJsonFiles(tempDir2); + + Map> jsonMap1 = parseJsonFiles(files1, tempDir1); + Map> jsonMap2 = parseJsonFiles(files2, tempDir2); + + Set fileNames1 = jsonMap1.keySet(); + Set fileNames2 = jsonMap2.keySet(); + + Set commonFileNames = new HashSet<>(fileNames1); + commonFileNames.retainAll(fileNames2); + + for (String fileName : commonFileNames) { + Map jsonMapFile1 = jsonMap1.get(fileName); + Map jsonMapFile2 = jsonMap2.get(fileName); + + if (jsonMapFile1 != null && jsonMapFile2 != null) { + Map fileDifferences = findDifferences(jsonMapFile1, jsonMapFile2); + if (!fileDifferences.isEmpty()) { + result.put(fileName, fileDifferences); + } + } + } + + Set missingInZip1 = findMissingFiles(fileNames1, fileNames2); + if (!missingInZip1.isEmpty()) { + result.putAll(missingFilesMap(missingInZip1, "Missing Files in UAT ZIP")); + } + + Set missingInZip2 = findMissingFiles(fileNames2, fileNames1); + if (!missingInZip2.isEmpty()) { + result.putAll(missingFilesMap(missingInZip2, "Missing Files in PROD ZIP")); + } + + } catch (IOException e) { + logger.error("Error comparing metadata ZIPs: " + e.getMessage(), e); + Map errorResult = new HashMap<>(); + errorResult.put("error", "Error comparing metadata ZIPs: " + e.getMessage()); + result.put("error", errorResult); + } finally { + if (tempDir1 != null) { + deleteDirectory(tempDir1); + } + if (tempDir2 != null) { + deleteDirectory(tempDir2); + } + } + return result; + } + + private File extractZip(MultipartFile zipFile) throws IOException { + File tempDir = Files.createTempDirectory("metadata-zip").toFile(); + + try (ZipInputStream zipInputStream = new ZipInputStream(zipFile.getInputStream())) { + ZipEntry entry; + while ((entry = zipInputStream.getNextEntry()) != null) { + if (!entry.isDirectory()) { + File file = new File(tempDir, entry.getName()); + File parentDir = file.getParentFile(); + if (!parentDir.exists()) { + parentDir.mkdirs(); + } + + try (OutputStream outputStream = new FileOutputStream(file)) { + byte[] buffer = new byte[1024]; + int length; + while ((length = zipInputStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, length); + } + } + } + zipInputStream.closeEntry(); + } + } + return tempDir; + } + + private List listJsonFiles(File directory) { + List jsonFiles = new ArrayList<>(); + File[] files = directory.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + jsonFiles.addAll(listJsonFiles(file)); + } else if (file.isFile() && file.getName().toLowerCase().endsWith(".json")) { + jsonFiles.add(file); + } + } + } + return jsonFiles; + } + + private Map> parseJsonFiles(List files, File rootDir) throws IOException { + Map> jsonMap = new HashMap<>(); + + for (File file : files) { + String relativePath = getRelativePath(file, rootDir); + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + StringBuilder jsonContent = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + jsonContent.append(line); + } + + Map jsonMapFile = new HashMap<>(); + if (jsonContent.toString().trim().startsWith("[")) { + List> jsonArray = objectMapper.readValue(jsonContent.toString(), new TypeReference>>() {}); + for (Map jsonObject : jsonArray) { + String uuid = (String) jsonObject.get("uuid"); + if (uuid != null) { + jsonObject.remove("filename"); + jsonMapFile.put(uuid, jsonObject); + } + } + } else { + Map jsonObject = objectMapper.readValue(jsonContent.toString(), new TypeReference>() {}); + String uuid = (String) jsonObject.get("uuid"); + if (uuid != null) { + jsonObject.remove("filename"); + jsonMapFile.put(uuid, jsonObject); + } + } + jsonMap.put(relativePath, jsonMapFile); + } + } + return jsonMap; + } + + private String getRelativePath(File file, File rootDir) { + String filePath = file.getPath(); + String rootPath = rootDir.getPath(); + return filePath.substring(rootPath.length() + 1); + } + + private Map findDifferences(Map jsonMap1, Map jsonMap2) { + Map differences = new HashMap<>(); + boolean hasDifferences = false; + String uuid = "null"; + for (Map.Entry entry : jsonMap1.entrySet()) { + uuid = entry.getKey(); + Object json1 = entry.getValue(); + Object json2 = jsonMap2.get(uuid); + if (json2 != null) { + Map diff = findJsonDifferences(castToStringObjectMap(json1), castToStringObjectMap(json2)); + if (!diff.isEmpty()) { + differences.put(uuid, diff); + hasDifferences = true; + } + } else { + differences.put(uuid, createFieldDiff(null, json1, "removed")); + hasDifferences = true; + } + } + + for (Map.Entry entry : jsonMap2.entrySet()) { + String uuid2 = entry.getKey(); + if (!jsonMap1.containsKey(uuid2)) { + differences.put(uuid2, createFieldDiff(null, entry.getValue(), "added")); + hasDifferences = true; + } + } + + if (!hasDifferences) { + differences.put(uuid, createFieldDiff(null, null, "noModification")); + } + return differences; + } + + private Map findJsonDifferences(Map json1, Map json2) { + Map differences = new LinkedHashMap<>(); + if (json1 == null && json2 == null) { + return differences; + } + + if (json1 == null) { + json2.forEach((key, value) -> differences.put(key, createFieldDiff(null, value, "added"))); + return differences; + } + + if (json2 == null) { + json1.forEach((key, value) -> differences.put(key, createFieldDiff(value, null, "removed"))); + return differences; + } + + for (Map.Entry entry : json1.entrySet()) { + String key = entry.getKey(); + Object value1 = entry.getValue(); + Object value2 = json2.get(key); + + if (key.equals("id")) { + continue; + } + if (value2 == null) { + differences.put(key, createFieldDiff(value1, null, "removed")); + } else { + if (value1 instanceof Map && value2 instanceof Map) { + Map subDiff = findJsonDifferences((Map) value1, (Map) value2); + if (!subDiff.isEmpty()) { + differences.put(key, createObjectDiff((Map) value1, (Map) value2, "modified")); + } + } else if (value1 instanceof List && value2 instanceof List) { + List> listDiff = findArrayDifferences((List) value1, (List) value2); + if (!listDiff.isEmpty()) { + differences.put(key, createArrayDiff((List) value1, (List) value2, "modified")); + } + } else if (!value1.equals(value2)) { + differences.put(key, createFieldDiff(value1, value2, "modified")); + } + } + } + + for (Map.Entry entry : json2.entrySet()) { + String key = entry.getKey(); + if (!json1.containsKey(key)) { + differences.put(key, createFieldDiff(null, entry.getValue(), "added")); + } + } + + return differences; + } + + private List> findArrayDifferences(List array1, List array2) { + List> differences = new ArrayList<>(); + int maxSize = Math.max(array1.size(), array2.size()); + + for (int i = 0; i < maxSize; i++) { + if (i >= array1.size()) { + differences.add(createFieldDiff(null, array2.get(i), "added")); + } else if (i >= array2.size()) { + differences.add(createFieldDiff(array1.get(i), null, "removed")); + } else { + Object value1 = array1.get(i); + Object value2 = array2.get(i); + + if (value1 instanceof Map && value2 instanceof Map) { + Map subDiff = findJsonDifferences(castToStringObjectMap(value1), castToStringObjectMap(value2)); + if (!subDiff.isEmpty()) { + differences.add(createObjectDiff(castToStringObjectMap(value1), castToStringObjectMap(value2), "modified")); + } + } else if (!value1.equals(value2)) { + differences.add(createFieldDiff(value1, value2, "modified")); + } + } + } + return differences; + } + + private Map createFieldDiff(Object oldValue, Object newValue, String changeType) { + Map fieldDiff = new LinkedHashMap<>(); + + if(!"noModification".equals(changeType)) { + if (oldValue == null && newValue != null) { + fieldDiff.put("dataType", getDataType(newValue)); + } else if (oldValue != null && newValue == null) { + fieldDiff.put("dataType", getDataType(oldValue)); + } else if (oldValue != null && newValue != null) { + fieldDiff.put("dataType", getDataType(newValue)); + } else { + fieldDiff.put("dataType", "object"); + } + } + fieldDiff.put("changeType", changeType); + if (oldValue != null) { + fieldDiff.put("oldValue", oldValue); + } + if (newValue != null) { + fieldDiff.put("newValue", newValue); + } + return fieldDiff; + } + + private Map createObjectDiff(Map oldValue, Map newValue, String changeType) { + Map objectDiff = new LinkedHashMap<>(); + Map fieldsDiff = findDifferences(oldValue, newValue); + + if (!fieldsDiff.isEmpty() && !"noModification".equals(changeType)) { + objectDiff.put("dataType", "object"); + objectDiff.put("changeType", changeType); + objectDiff.put("fields", fieldsDiff); + } + return objectDiff; + } + + private Map createArrayDiff(List oldValue, List newValue, String changeType) { + Map arrayDiff = new LinkedHashMap<>(); + + List> itemsDiff = findArrayDifferences(oldValue, newValue); + if (!itemsDiff.isEmpty() && !"noModification".equals(changeType)) { + arrayDiff.put("dataType", "array"); + arrayDiff.put("changeType", changeType); + arrayDiff.put("items", itemsDiff); + } + return arrayDiff; + } + + private Set findMissingFiles(Set fileNames1, Set fileNames2) { + Set missingFiles = new HashSet<>(fileNames1); + missingFiles.removeAll(fileNames2); + return missingFiles; + } + + private Map missingFilesMap(Set missingFiles, String message) { + Map missingFilesMap = new LinkedHashMap<>(); + missingFilesMap.put("message", message); + missingFilesMap.put("files", missingFiles); + return missingFilesMap; + } + + private void deleteDirectory(File directory) { + File[] files = directory.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + deleteDirectory(file); + } else { + file.delete(); + } + } + } + directory.delete(); + } + + private String getDataType(Object value) { + if (value instanceof Map) { + return "object"; + } else if (value instanceof List) { + return "array"; + } else { + return "primitive"; + } + } + + @SuppressWarnings("unchecked") + private Map castToStringObjectMap(Object obj) { + if (obj instanceof Map) { + return (Map) obj; + } + return new HashMap<>(); + } +} diff --git a/avni-server-api/src/main/java/org/avni/server/web/MetadataDiffController.java b/avni-server-api/src/main/java/org/avni/server/web/MetadataDiffController.java new file mode 100644 index 000000000..ce4199669 --- /dev/null +++ b/avni-server-api/src/main/java/org/avni/server/web/MetadataDiffController.java @@ -0,0 +1,32 @@ +package org.avni.server.web; + +import org.avni.server.service.MetadataDiffService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.*; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Map; + +@RestController +@RequestMapping("/api") +public class MetadataDiffController { + private final MetadataDiffService metadatadiffService; + + @Autowired + public MetadataDiffController(MetadataDiffService metadatadiffService) { + this.metadatadiffService = metadatadiffService; + } + + @PostMapping("/compare-metadata") + @PreAuthorize("hasAnyAuthority('user')") + public ResponseEntity compareMetadataZips(@RequestParam("file1") MultipartFile file1, + @RequestParam("file2") MultipartFile file2) throws IOException { + + Map result = metadatadiffService.compareMetadataZips(file1, file2); + + return ResponseEntity.ok(result); + } +} diff --git a/avni-server-api/src/test/java/org/avni/server/web/MetadataDiffControllerIntegrationTest.java b/avni-server-api/src/test/java/org/avni/server/web/MetadataDiffControllerIntegrationTest.java new file mode 100644 index 000000000..71eb2caa8 --- /dev/null +++ b/avni-server-api/src/test/java/org/avni/server/web/MetadataDiffControllerIntegrationTest.java @@ -0,0 +1,25 @@ +package org.avni.server.web; + +import org.avni.server.common.AbstractControllerIntegrationTest; +import org.junit.Test; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + +public class MetadataDiffControllerIntegrationTest extends AbstractControllerIntegrationTest { + + @Test + public void testCompareMetadataZips() throws Exception { + setUser("demo-user"); + MockMultipartFile file1 = new MockMultipartFile("file1", "file1.zip", MediaType.MULTIPART_FORM_DATA_VALUE, "zip file content".getBytes()); + MockMultipartFile file2 = new MockMultipartFile("file2", "file2.zip", MediaType.MULTIPART_FORM_DATA_VALUE, "zip file content".getBytes()); + + mockMvc.perform(MockMvcRequestBuilders.multipart("/api/compare-metadata") + .file(file1) + .file(file2)) + .andExpect(status().isOk()); + } +} \ No newline at end of file From 11661fd2e451ec0eda166eaa154aa379e92af6ec Mon Sep 17 00:00:00 2001 From: shraddha singh Date: Thu, 22 Aug 2024 16:13:52 +0530 Subject: [PATCH 2/8] MetadataDiffservice test file --- .../server/service/MetadataDiffService.java | 12 +-- .../service/MetadataDiffServiceTest.java | 95 +++++++++++++++++++ 2 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 avni-server-api/src/test/java/org/avni/server/service/MetadataDiffServiceTest.java diff --git a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java index 9d8fb0aa0..af4b51e80 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java +++ b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java @@ -162,7 +162,7 @@ private String getRelativePath(File file, File rootDir) { return filePath.substring(rootPath.length() + 1); } - private Map findDifferences(Map jsonMap1, Map jsonMap2) { + protected Map findDifferences(Map jsonMap1, Map jsonMap2) { Map differences = new HashMap<>(); boolean hasDifferences = false; String uuid = "null"; @@ -196,7 +196,7 @@ private Map findDifferences(Map jsonMap1, Map findJsonDifferences(Map json1, Map json2) { + protected Map findJsonDifferences(Map json1, Map json2) { Map differences = new LinkedHashMap<>(); if (json1 == null && json2 == null) { return differences; @@ -249,7 +249,7 @@ private Map findJsonDifferences(Map json1, Map> findArrayDifferences(List array1, List array2) { + protected List> findArrayDifferences(List array1, List array2) { List> differences = new ArrayList<>(); int maxSize = Math.max(array1.size(), array2.size()); @@ -323,20 +323,20 @@ private Map createArrayDiff(List oldValue, List return arrayDiff; } - private Set findMissingFiles(Set fileNames1, Set fileNames2) { + protected Set findMissingFiles(Set fileNames1, Set fileNames2) { Set missingFiles = new HashSet<>(fileNames1); missingFiles.removeAll(fileNames2); return missingFiles; } - private Map missingFilesMap(Set missingFiles, String message) { + protected Map missingFilesMap(Set missingFiles, String message) { Map missingFilesMap = new LinkedHashMap<>(); missingFilesMap.put("message", message); missingFilesMap.put("files", missingFiles); return missingFilesMap; } - private void deleteDirectory(File directory) { + protected void deleteDirectory(File directory) { File[] files = directory.listFiles(); if (files != null) { for (File file : files) { diff --git a/avni-server-api/src/test/java/org/avni/server/service/MetadataDiffServiceTest.java b/avni-server-api/src/test/java/org/avni/server/service/MetadataDiffServiceTest.java new file mode 100644 index 000000000..a287ddf67 --- /dev/null +++ b/avni-server-api/src/test/java/org/avni/server/service/MetadataDiffServiceTest.java @@ -0,0 +1,95 @@ +package org.avni.server.service; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.MockitoAnnotations; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.web.multipart.MultipartFile; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class MetadataDiffServiceTest { + + private MetadataDiffService metadataDiffService; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + metadataDiffService = new MetadataDiffService(); + } + + @Test + public void testCompareMetadataZips() throws IOException { + MultipartFile zipFile1 = createMultipartFile("file1.json", "{\"key\":\"value1\"}"); + MultipartFile zipFile2 = createMultipartFile("file1.json", "{\"key\":\"value2\"}"); + + assertNotNull(zipFile1); + assertNotNull(zipFile2); + + Map differences = metadataDiffService.compareMetadataZips(zipFile1, zipFile2); + + assertNotNull(differences); + assertEquals(1, differences.size()); + } + + private MultipartFile createMultipartFile(String fileName, String jsonContent) throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) { + ZipEntry zipEntry = new ZipEntry(fileName); + zipOutputStream.putNextEntry(zipEntry); + zipOutputStream.write(jsonContent.getBytes()); + zipOutputStream.closeEntry(); + } + return new MockMultipartFile("file", "test.zip", "application/zip", byteArrayOutputStream.toByteArray()); + } + + @Test + public void testFindDifferences() { + Map jsonMap1 = new HashMap<>(); + Map jsonMap2 = new HashMap<>(); + + jsonMap1.put("uuid1", createJsonObject("value1")); + jsonMap2.put("uuid1", createJsonObject("value2")); + jsonMap2.put("uuid2", createJsonObject("value3")); + + Map differences = metadataDiffService.findDifferences(jsonMap1, jsonMap2); + + assertNotNull(differences); + + assertTrue(differences.containsKey("uuid1")); + assertTrue(differences.containsKey("uuid2")); + } + + @Test + public void testFindMissingFiles() { + Set fileNames1 = new HashSet<>(); + Set fileNames2 = new HashSet<>(); + + fileNames1.add("file1.json"); + fileNames1.add("file2.json"); + fileNames2.add("file1.json"); + + Set missingFiles = metadataDiffService.findMissingFiles(fileNames1, fileNames2); + + assertNotNull(missingFiles); + + assertTrue(missingFiles.contains("file2.json")); + assertFalse(missingFiles.contains("file1.json")); + } + + private Map createJsonObject(String value) { + Map jsonObject = new HashMap<>(); + jsonObject.put("key", value); + return jsonObject; + } +} From 408005b955283cca2837986ee84e078a9cbb4ee6 Mon Sep 17 00:00:00 2001 From: shraddha singh Date: Tue, 27 Aug 2024 18:19:31 +0530 Subject: [PATCH 3/8] findArrayDifference updation --- .../server/service/MetadataDiffService.java | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java index af4b51e80..d8b1a6b7e 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java +++ b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java @@ -10,6 +10,7 @@ import java.io.*; import java.nio.file.Files; import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -251,27 +252,38 @@ protected Map findJsonDifferences(Map json1, Map protected List> findArrayDifferences(List array1, List array2) { List> differences = new ArrayList<>(); - int maxSize = Math.max(array1.size(), array2.size()); - for (int i = 0; i < maxSize; i++) { - if (i >= array1.size()) { - differences.add(createFieldDiff(null, array2.get(i), "added")); - } else if (i >= array2.size()) { - differences.add(createFieldDiff(array1.get(i), null, "removed")); + Function, String> getUuid = obj -> (String) obj.get("uuid"); + + Map> map1 = array1.stream() + .filter(obj -> obj instanceof Map) + .map(obj -> (Map) obj) + .collect(Collectors.toMap(getUuid, Function.identity(), (e1, e2) -> e1)); + + Map> map2 = array2.stream() + .filter(obj -> obj instanceof Map) + .map(obj -> (Map) obj) + .collect(Collectors.toMap(getUuid, Function.identity(), (e1, e2) -> e1)); + + for (String uuid : map2.keySet()) { + if (!map1.containsKey(uuid)) { + differences.add(createFieldDiff(null, map2.get(uuid), "added")); } else { - Object value1 = array1.get(i); - Object value2 = array2.get(i); + Map obj1 = map1.get(uuid); + Map obj2 = map2.get(uuid); - if (value1 instanceof Map && value2 instanceof Map) { - Map subDiff = findJsonDifferences(castToStringObjectMap(value1), castToStringObjectMap(value2)); - if (!subDiff.isEmpty()) { - differences.add(createObjectDiff(castToStringObjectMap(value1), castToStringObjectMap(value2), "modified")); - } - } else if (!value1.equals(value2)) { - differences.add(createFieldDiff(value1, value2, "modified")); + Map subDiff = findJsonDifferences(obj1, obj2); + if (!subDiff.isEmpty()) { + differences.add(createObjectDiff(obj1, obj2, "modified")); } } } + + for (String uuid : map1.keySet()) { + if (!map2.containsKey(uuid)) { + differences.add(createFieldDiff(map1.get(uuid), null, "removed")); + } + } return differences; } From 1d074ce228add2cf4fcf958902b0107a2d16bcf4 Mon Sep 17 00:00:00 2001 From: shraddha singh Date: Thu, 12 Sep 2024 16:20:54 +0530 Subject: [PATCH 4/8] MetadataDiff --- .../java/org/avni/server/service/MetadataDiffService.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java index d8b1a6b7e..61f9661c1 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java +++ b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java @@ -178,7 +178,7 @@ protected Map findDifferences(Map jsonMap1, Map< hasDifferences = true; } } else { - differences.put(uuid, createFieldDiff(null, json1, "removed")); + differences.put(uuid, createFieldDiff( json1, null,"removed")); hasDifferences = true; } } @@ -343,8 +343,7 @@ protected Set findMissingFiles(Set fileNames1, Set fileN protected Map missingFilesMap(Set missingFiles, String message) { Map missingFilesMap = new LinkedHashMap<>(); - missingFilesMap.put("message", message); - missingFilesMap.put("files", missingFiles); + missingFilesMap.put(message, missingFiles); return missingFilesMap; } @@ -372,7 +371,6 @@ private String getDataType(Object value) { } } - @SuppressWarnings("unchecked") private Map castToStringObjectMap(Object obj) { if (obj instanceof Map) { return (Map) obj; From 4d1672fa50288e27bb3912ac708b65cd41f25ddd Mon Sep 17 00:00:00 2001 From: shraddha singh Date: Thu, 19 Sep 2024 11:11:44 +0530 Subject: [PATCH 5/8] Micro services, refractoring --- .../service/MetadataBundleAndFileHandler.java | 106 ++++++ .../server/service/MetadataDiffChecker.java | 142 ++++++++ .../service/MetadataDiffOutputGenerator.java | 69 ++++ .../server/service/MetadataDiffService.java | 303 +----------------- .../service/MetadataDiffServiceTest.java | 15 +- 5 files changed, 343 insertions(+), 292 deletions(-) create mode 100644 avni-server-api/src/main/java/org/avni/server/service/MetadataBundleAndFileHandler.java create mode 100644 avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java create mode 100644 avni-server-api/src/main/java/org/avni/server/service/MetadataDiffOutputGenerator.java diff --git a/avni-server-api/src/main/java/org/avni/server/service/MetadataBundleAndFileHandler.java b/avni-server-api/src/main/java/org/avni/server/service/MetadataBundleAndFileHandler.java new file mode 100644 index 000000000..aa8fd44a8 --- /dev/null +++ b/avni-server-api/src/main/java/org/avni/server/service/MetadataBundleAndFileHandler.java @@ -0,0 +1,106 @@ +package org.avni.server.service; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +@Service +public class MetadataBundleAndFileHandler { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + protected File extractZip(MultipartFile zipFile) throws IOException { + File tempDir = Files.createTempDirectory("metadata-zip").toFile(); + + try (ZipInputStream zipInputStream = new ZipInputStream(zipFile.getInputStream())) { + ZipEntry entry; + while ((entry = zipInputStream.getNextEntry()) != null) { + if (!entry.isDirectory()) { + File file = new File(tempDir, entry.getName()); + File parentDir = file.getParentFile(); + if (!parentDir.exists()) { + parentDir.mkdirs(); + } + + try (OutputStream outputStream = new FileOutputStream(file)) { + byte[] buffer = new byte[1024]; + int length; + while ((length = zipInputStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, length); + } + } + } + zipInputStream.closeEntry(); + } + } + return tempDir; + } + + protected List listJsonFiles(File directory) { + List jsonFiles = new ArrayList<>(); + File[] files = directory.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + jsonFiles.addAll(listJsonFiles(file)); + } else if (file.isFile() && file.getName().toLowerCase().endsWith(".json")) { + jsonFiles.add(file); + } + } + } + return jsonFiles; + } + + protected Map> parseJsonFiles(List files, File rootDir) throws IOException { + Map> jsonMap = new HashMap<>(); + + for (File file : files) { + String relativePath = getRelativePath(file, rootDir); + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + StringBuilder jsonContent = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + jsonContent.append(line); + } + + Map jsonMapFile = new HashMap<>(); + if (jsonContent.toString().trim().startsWith("[")) { + List> jsonArray = objectMapper.readValue(jsonContent.toString(), new TypeReference>>() {}); + for (Map jsonObject : jsonArray) { + String uuid = (String) jsonObject.get("uuid"); + if (uuid != null) { + jsonObject.remove("filename"); + jsonMapFile.put(uuid, jsonObject); + } + } + } else { + Map jsonObject = objectMapper.readValue(jsonContent.toString(), new TypeReference>() {}); + String uuid = (String) jsonObject.get("uuid"); + if (uuid != null) { + jsonObject.remove("filename"); + jsonMapFile.put(uuid, jsonObject); + } + } + jsonMap.put(relativePath, jsonMapFile); + } + } + return jsonMap; + } + private String getRelativePath(File file, File rootDir) { + String filePath = file.getPath(); + String rootPath = rootDir.getPath(); + return filePath.substring(rootPath.length() + 1); + } +} diff --git a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java new file mode 100644 index 000000000..3c66478ef --- /dev/null +++ b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java @@ -0,0 +1,142 @@ +package org.avni.server.service; + +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Service +public class MetadataDiffChecker { + + MetadataDiffOutputGenerator metadataDiffOutputGenerator; + protected Map findDifferences(Map jsonMap1, Map jsonMap2) { + Map differences = new HashMap<>(); + boolean hasDifferences = false; + String uuid = "null"; + for (Map.Entry entry : jsonMap1.entrySet()) { + uuid = entry.getKey(); + Object json1 = entry.getValue(); + Object json2 = jsonMap2.get(uuid); + if (json2 != null) { + Map diff = findJsonDifferences(castToStringObjectMap(json1), castToStringObjectMap(json2)); + if (!diff.isEmpty()) { + differences.put(uuid, diff); + hasDifferences = true; + } + } else { + differences.put(uuid, metadataDiffOutputGenerator.createFieldDiff( json1, null,"removed")); + hasDifferences = true; + } + } + + for (Map.Entry entry : jsonMap2.entrySet()) { + String uuid2 = entry.getKey(); + if (!jsonMap1.containsKey(uuid2)) { + differences.put(uuid2, metadataDiffOutputGenerator.createFieldDiff(null, entry.getValue(), "added")); + hasDifferences = true; + } + } + + if (!hasDifferences) { + differences.put(uuid, metadataDiffOutputGenerator.createFieldDiff(null, null, "noModification")); + } + return differences; + } + + protected Map findJsonDifferences(Map json1, Map json2) { + Map differences = new LinkedHashMap<>(); + if (json1 == null && json2 == null) { + return differences; + } + + if (json1 == null) { + json2.forEach((key, value) -> differences.put(key, metadataDiffOutputGenerator.createFieldDiff(null, value, "added"))); + return differences; + } + + if (json2 == null) { + json1.forEach((key, value) -> differences.put(key, metadataDiffOutputGenerator.createFieldDiff(value, null, "removed"))); + return differences; + } + + for (Map.Entry entry : json1.entrySet()) { + String key = entry.getKey(); + Object value1 = entry.getValue(); + Object value2 = json2.get(key); + + if (key.equals("id")) { + continue; + } + if (value2 == null) { + differences.put(key, metadataDiffOutputGenerator.createFieldDiff(value1, null, "removed")); + } else { + if (value1 instanceof Map && value2 instanceof Map) { + Map subDiff = findJsonDifferences((Map) value1, (Map) value2); + if (!subDiff.isEmpty()) { + differences.put(key, metadataDiffOutputGenerator.createObjectDiff((Map) value1, (Map) value2, "modified")); + } + } else if (value1 instanceof List && value2 instanceof List) { + List> listDiff = findArrayDifferences((List) value1, (List) value2); + if (!listDiff.isEmpty()) { + differences.put(key, metadataDiffOutputGenerator.createArrayDiff((List) value1, (List) value2, "modified")); + } + } else if (!value1.equals(value2)) { + differences.put(key, metadataDiffOutputGenerator.createFieldDiff(value1, value2, "modified")); + } + } + } + + for (Map.Entry entry : json2.entrySet()) { + String key = entry.getKey(); + if (!json1.containsKey(key)) { + differences.put(key, metadataDiffOutputGenerator.createFieldDiff(null, entry.getValue(), "added")); + } + } + + return differences; + } + + protected List> findArrayDifferences(List array1, List array2) { + List> differences = new ArrayList<>(); + + Function, String> getUuid = obj -> (String) obj.get("uuid"); + + Map> map1 = array1.stream() + .filter(obj -> obj instanceof Map) + .map(obj -> (Map) obj) + .collect(Collectors.toMap(getUuid, Function.identity(), (e1, e2) -> e1)); + + Map> map2 = array2.stream() + .filter(obj -> obj instanceof Map) + .map(obj -> (Map) obj) + .collect(Collectors.toMap(getUuid, Function.identity(), (e1, e2) -> e1)); + + for (String uuid : map2.keySet()) { + if (!map1.containsKey(uuid)) { + differences.add(metadataDiffOutputGenerator.createFieldDiff(null, map2.get(uuid), "added")); + } else { + Map obj1 = map1.get(uuid); + Map obj2 = map2.get(uuid); + + Map subDiff = findJsonDifferences(obj1, obj2); + if (!subDiff.isEmpty()) { + differences.add(metadataDiffOutputGenerator.createObjectDiff(obj1, obj2, "modified")); + } + } + } + + for (String uuid : map1.keySet()) { + if (!map2.containsKey(uuid)) { + differences.add(metadataDiffOutputGenerator.createFieldDiff(map1.get(uuid), null, "removed")); + } + } + return differences; + } + private Map castToStringObjectMap(Object obj) { + if (obj instanceof Map) { + return (Map) obj; + } + return new HashMap<>(); + } +} diff --git a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffOutputGenerator.java b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffOutputGenerator.java new file mode 100644 index 000000000..9da670b9d --- /dev/null +++ b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffOutputGenerator.java @@ -0,0 +1,69 @@ +package org.avni.server.service; + +import org.springframework.stereotype.Service; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +@Service +public class MetadataDiffOutputGenerator { + MetadataDiffChecker metadataDiffChecker; + + protected Map createFieldDiff(Object oldValue, Object newValue, String changeType) { + Map fieldDiff = new LinkedHashMap<>(); + + if(!"noModification".equals(changeType)) { + if (oldValue == null && newValue != null) { + fieldDiff.put("dataType", getDataType(newValue)); + } else if (oldValue != null && newValue == null) { + fieldDiff.put("dataType", getDataType(oldValue)); + } else if (oldValue != null && newValue != null) { + fieldDiff.put("dataType", getDataType(newValue)); + } else { + fieldDiff.put("dataType", "object"); + } + } + fieldDiff.put("changeType", changeType); + if (oldValue != null) { + fieldDiff.put("oldValue", oldValue); + } + if (newValue != null) { + fieldDiff.put("newValue", newValue); + } + return fieldDiff; + } + + protected Map createObjectDiff(Map oldValue, Map newValue, String changeType) { + Map objectDiff = new LinkedHashMap<>(); + Map fieldsDiff = metadataDiffChecker.findDifferences(oldValue, newValue); + + if (!fieldsDiff.isEmpty() && !"noModification".equals(changeType)) { + objectDiff.put("dataType", "object"); + objectDiff.put("changeType", changeType); + objectDiff.put("fields", fieldsDiff); + } + return objectDiff; + } + + protected Map createArrayDiff(List oldValue, List newValue, String changeType) { + Map arrayDiff = new LinkedHashMap<>(); + + List> itemsDiff = metadataDiffChecker.findArrayDifferences(oldValue, newValue); + if (!itemsDiff.isEmpty() && !"noModification".equals(changeType)) { + arrayDiff.put("dataType", "array"); + arrayDiff.put("changeType", changeType); + arrayDiff.put("items", itemsDiff); + } + return arrayDiff; + } + private String getDataType(Object value) { + if (value instanceof Map) { + return "object"; + } else if (value instanceof List) { + return "array"; + } else { + return "primitive"; + } + } +} diff --git a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java index 61f9661c1..10348a2ab 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java +++ b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffService.java @@ -5,15 +5,9 @@ import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.core.type.TypeReference; import java.io.*; -import java.nio.file.Files; import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; @Service public class MetadataDiffService { @@ -21,19 +15,29 @@ public class MetadataDiffService { private static final Logger logger = LoggerFactory.getLogger(MetadataDiffService.class); private static final ObjectMapper objectMapper = new ObjectMapper(); + private final MetadataBundleAndFileHandler bundleAndFileHandler; + private final MetadataDiffChecker diffChecker; + private final MetadataDiffOutputGenerator outputGenerator; + + public MetadataDiffService(MetadataBundleAndFileHandler bundleAndFileHandler, MetadataDiffChecker diffChecker, MetadataDiffOutputGenerator outputGenerator) { + this.bundleAndFileHandler = bundleAndFileHandler; + this.diffChecker = diffChecker; + this.outputGenerator = outputGenerator; + } + public Map compareMetadataZips(MultipartFile zipFile1, MultipartFile zipFile2) throws IOException { Map result = new HashMap<>(); File tempDir1 = null, tempDir2 = null; try { - tempDir1 = extractZip(zipFile1); - tempDir2 = extractZip(zipFile2); + tempDir1 = bundleAndFileHandler.extractZip(zipFile1); + tempDir2 = bundleAndFileHandler.extractZip(zipFile2); - List files1 = listJsonFiles(tempDir1); - List files2 = listJsonFiles(tempDir2); + List files1 = bundleAndFileHandler.listJsonFiles(tempDir1); + List files2 = bundleAndFileHandler.listJsonFiles(tempDir2); - Map> jsonMap1 = parseJsonFiles(files1, tempDir1); - Map> jsonMap2 = parseJsonFiles(files2, tempDir2); + Map> jsonMap1 = bundleAndFileHandler.parseJsonFiles(files1, tempDir1); + Map> jsonMap2 = bundleAndFileHandler.parseJsonFiles(files2, tempDir2); Set fileNames1 = jsonMap1.keySet(); Set fileNames2 = jsonMap2.keySet(); @@ -46,7 +50,7 @@ public Map compareMetadataZips(MultipartFile zipFile1, Multipart Map jsonMapFile2 = jsonMap2.get(fileName); if (jsonMapFile1 != null && jsonMapFile2 != null) { - Map fileDifferences = findDifferences(jsonMapFile1, jsonMapFile2); + Map fileDifferences = diffChecker.findDifferences(jsonMapFile1, jsonMapFile2); if (!fileDifferences.isEmpty()) { result.put(fileName, fileDifferences); } @@ -79,262 +83,6 @@ public Map compareMetadataZips(MultipartFile zipFile1, Multipart return result; } - private File extractZip(MultipartFile zipFile) throws IOException { - File tempDir = Files.createTempDirectory("metadata-zip").toFile(); - - try (ZipInputStream zipInputStream = new ZipInputStream(zipFile.getInputStream())) { - ZipEntry entry; - while ((entry = zipInputStream.getNextEntry()) != null) { - if (!entry.isDirectory()) { - File file = new File(tempDir, entry.getName()); - File parentDir = file.getParentFile(); - if (!parentDir.exists()) { - parentDir.mkdirs(); - } - - try (OutputStream outputStream = new FileOutputStream(file)) { - byte[] buffer = new byte[1024]; - int length; - while ((length = zipInputStream.read(buffer)) > 0) { - outputStream.write(buffer, 0, length); - } - } - } - zipInputStream.closeEntry(); - } - } - return tempDir; - } - - private List listJsonFiles(File directory) { - List jsonFiles = new ArrayList<>(); - File[] files = directory.listFiles(); - if (files != null) { - for (File file : files) { - if (file.isDirectory()) { - jsonFiles.addAll(listJsonFiles(file)); - } else if (file.isFile() && file.getName().toLowerCase().endsWith(".json")) { - jsonFiles.add(file); - } - } - } - return jsonFiles; - } - - private Map> parseJsonFiles(List files, File rootDir) throws IOException { - Map> jsonMap = new HashMap<>(); - - for (File file : files) { - String relativePath = getRelativePath(file, rootDir); - try (BufferedReader reader = new BufferedReader(new FileReader(file))) { - StringBuilder jsonContent = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - jsonContent.append(line); - } - - Map jsonMapFile = new HashMap<>(); - if (jsonContent.toString().trim().startsWith("[")) { - List> jsonArray = objectMapper.readValue(jsonContent.toString(), new TypeReference>>() {}); - for (Map jsonObject : jsonArray) { - String uuid = (String) jsonObject.get("uuid"); - if (uuid != null) { - jsonObject.remove("filename"); - jsonMapFile.put(uuid, jsonObject); - } - } - } else { - Map jsonObject = objectMapper.readValue(jsonContent.toString(), new TypeReference>() {}); - String uuid = (String) jsonObject.get("uuid"); - if (uuid != null) { - jsonObject.remove("filename"); - jsonMapFile.put(uuid, jsonObject); - } - } - jsonMap.put(relativePath, jsonMapFile); - } - } - return jsonMap; - } - - private String getRelativePath(File file, File rootDir) { - String filePath = file.getPath(); - String rootPath = rootDir.getPath(); - return filePath.substring(rootPath.length() + 1); - } - - protected Map findDifferences(Map jsonMap1, Map jsonMap2) { - Map differences = new HashMap<>(); - boolean hasDifferences = false; - String uuid = "null"; - for (Map.Entry entry : jsonMap1.entrySet()) { - uuid = entry.getKey(); - Object json1 = entry.getValue(); - Object json2 = jsonMap2.get(uuid); - if (json2 != null) { - Map diff = findJsonDifferences(castToStringObjectMap(json1), castToStringObjectMap(json2)); - if (!diff.isEmpty()) { - differences.put(uuid, diff); - hasDifferences = true; - } - } else { - differences.put(uuid, createFieldDiff( json1, null,"removed")); - hasDifferences = true; - } - } - - for (Map.Entry entry : jsonMap2.entrySet()) { - String uuid2 = entry.getKey(); - if (!jsonMap1.containsKey(uuid2)) { - differences.put(uuid2, createFieldDiff(null, entry.getValue(), "added")); - hasDifferences = true; - } - } - - if (!hasDifferences) { - differences.put(uuid, createFieldDiff(null, null, "noModification")); - } - return differences; - } - - protected Map findJsonDifferences(Map json1, Map json2) { - Map differences = new LinkedHashMap<>(); - if (json1 == null && json2 == null) { - return differences; - } - - if (json1 == null) { - json2.forEach((key, value) -> differences.put(key, createFieldDiff(null, value, "added"))); - return differences; - } - - if (json2 == null) { - json1.forEach((key, value) -> differences.put(key, createFieldDiff(value, null, "removed"))); - return differences; - } - - for (Map.Entry entry : json1.entrySet()) { - String key = entry.getKey(); - Object value1 = entry.getValue(); - Object value2 = json2.get(key); - - if (key.equals("id")) { - continue; - } - if (value2 == null) { - differences.put(key, createFieldDiff(value1, null, "removed")); - } else { - if (value1 instanceof Map && value2 instanceof Map) { - Map subDiff = findJsonDifferences((Map) value1, (Map) value2); - if (!subDiff.isEmpty()) { - differences.put(key, createObjectDiff((Map) value1, (Map) value2, "modified")); - } - } else if (value1 instanceof List && value2 instanceof List) { - List> listDiff = findArrayDifferences((List) value1, (List) value2); - if (!listDiff.isEmpty()) { - differences.put(key, createArrayDiff((List) value1, (List) value2, "modified")); - } - } else if (!value1.equals(value2)) { - differences.put(key, createFieldDiff(value1, value2, "modified")); - } - } - } - - for (Map.Entry entry : json2.entrySet()) { - String key = entry.getKey(); - if (!json1.containsKey(key)) { - differences.put(key, createFieldDiff(null, entry.getValue(), "added")); - } - } - - return differences; - } - - protected List> findArrayDifferences(List array1, List array2) { - List> differences = new ArrayList<>(); - - Function, String> getUuid = obj -> (String) obj.get("uuid"); - - Map> map1 = array1.stream() - .filter(obj -> obj instanceof Map) - .map(obj -> (Map) obj) - .collect(Collectors.toMap(getUuid, Function.identity(), (e1, e2) -> e1)); - - Map> map2 = array2.stream() - .filter(obj -> obj instanceof Map) - .map(obj -> (Map) obj) - .collect(Collectors.toMap(getUuid, Function.identity(), (e1, e2) -> e1)); - - for (String uuid : map2.keySet()) { - if (!map1.containsKey(uuid)) { - differences.add(createFieldDiff(null, map2.get(uuid), "added")); - } else { - Map obj1 = map1.get(uuid); - Map obj2 = map2.get(uuid); - - Map subDiff = findJsonDifferences(obj1, obj2); - if (!subDiff.isEmpty()) { - differences.add(createObjectDiff(obj1, obj2, "modified")); - } - } - } - - for (String uuid : map1.keySet()) { - if (!map2.containsKey(uuid)) { - differences.add(createFieldDiff(map1.get(uuid), null, "removed")); - } - } - return differences; - } - - private Map createFieldDiff(Object oldValue, Object newValue, String changeType) { - Map fieldDiff = new LinkedHashMap<>(); - - if(!"noModification".equals(changeType)) { - if (oldValue == null && newValue != null) { - fieldDiff.put("dataType", getDataType(newValue)); - } else if (oldValue != null && newValue == null) { - fieldDiff.put("dataType", getDataType(oldValue)); - } else if (oldValue != null && newValue != null) { - fieldDiff.put("dataType", getDataType(newValue)); - } else { - fieldDiff.put("dataType", "object"); - } - } - fieldDiff.put("changeType", changeType); - if (oldValue != null) { - fieldDiff.put("oldValue", oldValue); - } - if (newValue != null) { - fieldDiff.put("newValue", newValue); - } - return fieldDiff; - } - - private Map createObjectDiff(Map oldValue, Map newValue, String changeType) { - Map objectDiff = new LinkedHashMap<>(); - Map fieldsDiff = findDifferences(oldValue, newValue); - - if (!fieldsDiff.isEmpty() && !"noModification".equals(changeType)) { - objectDiff.put("dataType", "object"); - objectDiff.put("changeType", changeType); - objectDiff.put("fields", fieldsDiff); - } - return objectDiff; - } - - private Map createArrayDiff(List oldValue, List newValue, String changeType) { - Map arrayDiff = new LinkedHashMap<>(); - - List> itemsDiff = findArrayDifferences(oldValue, newValue); - if (!itemsDiff.isEmpty() && !"noModification".equals(changeType)) { - arrayDiff.put("dataType", "array"); - arrayDiff.put("changeType", changeType); - arrayDiff.put("items", itemsDiff); - } - return arrayDiff; - } - protected Set findMissingFiles(Set fileNames1, Set fileNames2) { Set missingFiles = new HashSet<>(fileNames1); missingFiles.removeAll(fileNames2); @@ -360,21 +108,4 @@ protected void deleteDirectory(File directory) { } directory.delete(); } - - private String getDataType(Object value) { - if (value instanceof Map) { - return "object"; - } else if (value instanceof List) { - return "array"; - } else { - return "primitive"; - } - } - - private Map castToStringObjectMap(Object obj) { - if (obj instanceof Map) { - return (Map) obj; - } - return new HashMap<>(); - } } diff --git a/avni-server-api/src/test/java/org/avni/server/service/MetadataDiffServiceTest.java b/avni-server-api/src/test/java/org/avni/server/service/MetadataDiffServiceTest.java index a287ddf67..53b5c1ebc 100644 --- a/avni-server-api/src/test/java/org/avni/server/service/MetadataDiffServiceTest.java +++ b/avni-server-api/src/test/java/org/avni/server/service/MetadataDiffServiceTest.java @@ -5,27 +5,30 @@ import org.junit.Before; import org.junit.Test; -import org.mockito.MockitoAnnotations; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.*; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; public class MetadataDiffServiceTest { + private MetadataBundleAndFileHandler bundleAndFileHandler; + private MetadataDiffChecker diffChecker; + private MetadataDiffOutputGenerator outputGenerator; private MetadataDiffService metadataDiffService; @Before public void setUp() { - MockitoAnnotations.initMocks(this); - metadataDiffService = new MetadataDiffService(); + bundleAndFileHandler = mock(MetadataBundleAndFileHandler.class); + diffChecker = mock(MetadataDiffChecker.class); + outputGenerator = mock(MetadataDiffOutputGenerator.class); + metadataDiffService = new MetadataDiffService(bundleAndFileHandler, diffChecker, outputGenerator); } @Test @@ -62,7 +65,7 @@ public void testFindDifferences() { jsonMap2.put("uuid1", createJsonObject("value2")); jsonMap2.put("uuid2", createJsonObject("value3")); - Map differences = metadataDiffService.findDifferences(jsonMap1, jsonMap2); + Map differences = diffChecker.findDifferences(jsonMap1, jsonMap2); assertNotNull(differences); From cf2569307d938b16abb2fe6053b766e653fcf74e Mon Sep 17 00:00:00 2001 From: shraddha singh Date: Thu, 19 Sep 2024 13:09:54 +0530 Subject: [PATCH 6/8] Replace all string literals with String constants --- .../server/service/MetadataDiffChecker.java | 31 +++++++----- .../service/MetadataDiffOutputGenerator.java | 50 ++++++++++++------- 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java index 3c66478ef..2da0f474f 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java +++ b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java @@ -9,6 +9,11 @@ @Service public class MetadataDiffChecker { + public static final String MODIFIED = "modified"; + public static final String ADDED = "added"; + public static final String REMOVED = "removed"; + public static final String NO_MODIFICATION = "noModification"; + MetadataDiffOutputGenerator metadataDiffOutputGenerator; protected Map findDifferences(Map jsonMap1, Map jsonMap2) { Map differences = new HashMap<>(); @@ -25,7 +30,7 @@ protected Map findDifferences(Map jsonMap1, Map< hasDifferences = true; } } else { - differences.put(uuid, metadataDiffOutputGenerator.createFieldDiff( json1, null,"removed")); + differences.put(uuid, metadataDiffOutputGenerator.createFieldDiff( json1, null,REMOVED)); hasDifferences = true; } } @@ -33,13 +38,13 @@ protected Map findDifferences(Map jsonMap1, Map< for (Map.Entry entry : jsonMap2.entrySet()) { String uuid2 = entry.getKey(); if (!jsonMap1.containsKey(uuid2)) { - differences.put(uuid2, metadataDiffOutputGenerator.createFieldDiff(null, entry.getValue(), "added")); + differences.put(uuid2, metadataDiffOutputGenerator.createFieldDiff(null, entry.getValue(), ADDED)); hasDifferences = true; } } if (!hasDifferences) { - differences.put(uuid, metadataDiffOutputGenerator.createFieldDiff(null, null, "noModification")); + differences.put(uuid, metadataDiffOutputGenerator.createFieldDiff(null, null, NO_MODIFICATION)); } return differences; } @@ -51,12 +56,12 @@ protected Map findJsonDifferences(Map json1, Map } if (json1 == null) { - json2.forEach((key, value) -> differences.put(key, metadataDiffOutputGenerator.createFieldDiff(null, value, "added"))); + json2.forEach((key, value) -> differences.put(key, metadataDiffOutputGenerator.createFieldDiff(null, value, ADDED))); return differences; } if (json2 == null) { - json1.forEach((key, value) -> differences.put(key, metadataDiffOutputGenerator.createFieldDiff(value, null, "removed"))); + json1.forEach((key, value) -> differences.put(key, metadataDiffOutputGenerator.createFieldDiff(value, null, REMOVED))); return differences; } @@ -69,20 +74,20 @@ protected Map findJsonDifferences(Map json1, Map continue; } if (value2 == null) { - differences.put(key, metadataDiffOutputGenerator.createFieldDiff(value1, null, "removed")); + differences.put(key, metadataDiffOutputGenerator.createFieldDiff(value1, null, REMOVED)); } else { if (value1 instanceof Map && value2 instanceof Map) { Map subDiff = findJsonDifferences((Map) value1, (Map) value2); if (!subDiff.isEmpty()) { - differences.put(key, metadataDiffOutputGenerator.createObjectDiff((Map) value1, (Map) value2, "modified")); + differences.put(key, metadataDiffOutputGenerator.createObjectDiff((Map) value1, (Map) value2, MODIFIED)); } } else if (value1 instanceof List && value2 instanceof List) { List> listDiff = findArrayDifferences((List) value1, (List) value2); if (!listDiff.isEmpty()) { - differences.put(key, metadataDiffOutputGenerator.createArrayDiff((List) value1, (List) value2, "modified")); + differences.put(key, metadataDiffOutputGenerator.createArrayDiff((List) value1, (List) value2, MODIFIED)); } } else if (!value1.equals(value2)) { - differences.put(key, metadataDiffOutputGenerator.createFieldDiff(value1, value2, "modified")); + differences.put(key, metadataDiffOutputGenerator.createFieldDiff(value1, value2, MODIFIED)); } } } @@ -90,7 +95,7 @@ protected Map findJsonDifferences(Map json1, Map for (Map.Entry entry : json2.entrySet()) { String key = entry.getKey(); if (!json1.containsKey(key)) { - differences.put(key, metadataDiffOutputGenerator.createFieldDiff(null, entry.getValue(), "added")); + differences.put(key, metadataDiffOutputGenerator.createFieldDiff(null, entry.getValue(), ADDED)); } } @@ -114,21 +119,21 @@ protected List> findArrayDifferences(List array1, Li for (String uuid : map2.keySet()) { if (!map1.containsKey(uuid)) { - differences.add(metadataDiffOutputGenerator.createFieldDiff(null, map2.get(uuid), "added")); + differences.add(metadataDiffOutputGenerator.createFieldDiff(null, map2.get(uuid), ADDED)); } else { Map obj1 = map1.get(uuid); Map obj2 = map2.get(uuid); Map subDiff = findJsonDifferences(obj1, obj2); if (!subDiff.isEmpty()) { - differences.add(metadataDiffOutputGenerator.createObjectDiff(obj1, obj2, "modified")); + differences.add(metadataDiffOutputGenerator.createObjectDiff(obj1, obj2, MODIFIED)); } } } for (String uuid : map1.keySet()) { if (!map2.containsKey(uuid)) { - differences.add(metadataDiffOutputGenerator.createFieldDiff(map1.get(uuid), null, "removed")); + differences.add(metadataDiffOutputGenerator.createFieldDiff(map1.get(uuid), null, REMOVED)); } } return differences; diff --git a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffOutputGenerator.java b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffOutputGenerator.java index 9da670b9d..dbe3efc3b 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffOutputGenerator.java +++ b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffOutputGenerator.java @@ -10,26 +10,38 @@ public class MetadataDiffOutputGenerator { MetadataDiffChecker metadataDiffChecker; + public static final String NO_MODIFICATION = "noModification"; + public static final String OLD_VALUE = "oldValue"; + public static final String NEW_VALUE = "newValue"; + public static final String CHANGE_TYPE = "changeType"; + public static final String DATA_TYPE = "dataType"; + public static final String OBJECT = "object"; + public static final String FIELD = "field"; + public static final String ARRAY = "array"; + public static final String PRIMITIVE = "primitive"; + public static final String ITEMS = "items"; + + protected Map createFieldDiff(Object oldValue, Object newValue, String changeType) { Map fieldDiff = new LinkedHashMap<>(); - if(!"noModification".equals(changeType)) { + if(!NO_MODIFICATION.equals(changeType)) { if (oldValue == null && newValue != null) { - fieldDiff.put("dataType", getDataType(newValue)); + fieldDiff.put(DATA_TYPE, getDataType(newValue)); } else if (oldValue != null && newValue == null) { - fieldDiff.put("dataType", getDataType(oldValue)); + fieldDiff.put(DATA_TYPE, getDataType(oldValue)); } else if (oldValue != null && newValue != null) { - fieldDiff.put("dataType", getDataType(newValue)); + fieldDiff.put(DATA_TYPE, getDataType(newValue)); } else { - fieldDiff.put("dataType", "object"); + fieldDiff.put(DATA_TYPE, OBJECT); } } - fieldDiff.put("changeType", changeType); + fieldDiff.put(CHANGE_TYPE, changeType); if (oldValue != null) { - fieldDiff.put("oldValue", oldValue); + fieldDiff.put(OLD_VALUE, oldValue); } if (newValue != null) { - fieldDiff.put("newValue", newValue); + fieldDiff.put(NEW_VALUE, newValue); } return fieldDiff; } @@ -38,10 +50,10 @@ protected Map createObjectDiff(Map oldValue, Map Map objectDiff = new LinkedHashMap<>(); Map fieldsDiff = metadataDiffChecker.findDifferences(oldValue, newValue); - if (!fieldsDiff.isEmpty() && !"noModification".equals(changeType)) { - objectDiff.put("dataType", "object"); - objectDiff.put("changeType", changeType); - objectDiff.put("fields", fieldsDiff); + if (!fieldsDiff.isEmpty() && !NO_MODIFICATION.equals(changeType)) { + objectDiff.put(DATA_TYPE, OBJECT); + objectDiff.put(CHANGE_TYPE, changeType); + objectDiff.put(FIELD, fieldsDiff); } return objectDiff; } @@ -50,20 +62,20 @@ protected Map createArrayDiff(List oldValue, List arrayDiff = new LinkedHashMap<>(); List> itemsDiff = metadataDiffChecker.findArrayDifferences(oldValue, newValue); - if (!itemsDiff.isEmpty() && !"noModification".equals(changeType)) { - arrayDiff.put("dataType", "array"); - arrayDiff.put("changeType", changeType); - arrayDiff.put("items", itemsDiff); + if (!itemsDiff.isEmpty() && !NO_MODIFICATION.equals(changeType)) { + arrayDiff.put(DATA_TYPE, ARRAY); + arrayDiff.put(CHANGE_TYPE, changeType); + arrayDiff.put(ITEMS, itemsDiff); } return arrayDiff; } private String getDataType(Object value) { if (value instanceof Map) { - return "object"; + return OBJECT; } else if (value instanceof List) { - return "array"; + return ARRAY; } else { - return "primitive"; + return PRIMITIVE; } } } From 7838ad0b9fc781cf0dce6a4e3cc3baedaaef4438 Mon Sep 17 00:00:00 2001 From: shraddha singh Date: Fri, 20 Sep 2024 08:36:07 +0530 Subject: [PATCH 7/8] Remove circular dependency --- .../avni/server/service/MetadataDiffChecker.java | 14 ++++++++++---- .../service/MetadataDiffOutputGenerator.java | 8 ++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java index 2da0f474f..26adbe40c 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java +++ b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java @@ -1,5 +1,6 @@ package org.avni.server.service; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.*; @@ -14,7 +15,12 @@ public class MetadataDiffChecker { public static final String REMOVED = "removed"; public static final String NO_MODIFICATION = "noModification"; - MetadataDiffOutputGenerator metadataDiffOutputGenerator; + MetadataDiffOutputGenerator metadataDiffOutputGenerator; + + public MetadataDiffChecker(MetadataDiffOutputGenerator metadataDiffOutputGenerator) { + this.metadataDiffOutputGenerator = metadataDiffOutputGenerator; + } + protected Map findDifferences(Map jsonMap1, Map jsonMap2) { Map differences = new HashMap<>(); boolean hasDifferences = false; @@ -79,12 +85,12 @@ protected Map findJsonDifferences(Map json1, Map if (value1 instanceof Map && value2 instanceof Map) { Map subDiff = findJsonDifferences((Map) value1, (Map) value2); if (!subDiff.isEmpty()) { - differences.put(key, metadataDiffOutputGenerator.createObjectDiff((Map) value1, (Map) value2, MODIFIED)); + differences.put(key, metadataDiffOutputGenerator.createObjectDiff(subDiff, MODIFIED)); } } else if (value1 instanceof List && value2 instanceof List) { List> listDiff = findArrayDifferences((List) value1, (List) value2); if (!listDiff.isEmpty()) { - differences.put(key, metadataDiffOutputGenerator.createArrayDiff((List) value1, (List) value2, MODIFIED)); + differences.put(key, metadataDiffOutputGenerator.createArrayDiff(listDiff, MODIFIED)); } } else if (!value1.equals(value2)) { differences.put(key, metadataDiffOutputGenerator.createFieldDiff(value1, value2, MODIFIED)); @@ -126,7 +132,7 @@ protected List> findArrayDifferences(List array1, Li Map subDiff = findJsonDifferences(obj1, obj2); if (!subDiff.isEmpty()) { - differences.add(metadataDiffOutputGenerator.createObjectDiff(obj1, obj2, MODIFIED)); + differences.add(metadataDiffOutputGenerator.createObjectDiff(subDiff, MODIFIED)); } } } diff --git a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffOutputGenerator.java b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffOutputGenerator.java index dbe3efc3b..07c8b4932 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffOutputGenerator.java +++ b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffOutputGenerator.java @@ -8,7 +8,6 @@ @Service public class MetadataDiffOutputGenerator { - MetadataDiffChecker metadataDiffChecker; public static final String NO_MODIFICATION = "noModification"; public static final String OLD_VALUE = "oldValue"; @@ -21,7 +20,6 @@ public class MetadataDiffOutputGenerator { public static final String PRIMITIVE = "primitive"; public static final String ITEMS = "items"; - protected Map createFieldDiff(Object oldValue, Object newValue, String changeType) { Map fieldDiff = new LinkedHashMap<>(); @@ -46,9 +44,8 @@ protected Map createFieldDiff(Object oldValue, Object newValue, return fieldDiff; } - protected Map createObjectDiff(Map oldValue, Map newValue, String changeType) { + protected Map createObjectDiff(Map fieldsDiff, String changeType) { Map objectDiff = new LinkedHashMap<>(); - Map fieldsDiff = metadataDiffChecker.findDifferences(oldValue, newValue); if (!fieldsDiff.isEmpty() && !NO_MODIFICATION.equals(changeType)) { objectDiff.put(DATA_TYPE, OBJECT); @@ -58,10 +55,9 @@ protected Map createObjectDiff(Map oldValue, Map return objectDiff; } - protected Map createArrayDiff(List oldValue, List newValue, String changeType) { + protected Map createArrayDiff(List> itemsDiff, String changeType) { Map arrayDiff = new LinkedHashMap<>(); - List> itemsDiff = metadataDiffChecker.findArrayDifferences(oldValue, newValue); if (!itemsDiff.isEmpty() && !NO_MODIFICATION.equals(changeType)) { arrayDiff.put(DATA_TYPE, ARRAY); arrayDiff.put(CHANGE_TYPE, changeType); From acc8e132fba09234cc9e619a88638ccc5e9ba5bf Mon Sep 17 00:00:00 2001 From: shraddha761 <106100728+shraddha761@users.noreply.github.com> Date: Fri, 20 Sep 2024 08:53:57 +0530 Subject: [PATCH 8/8] Remove unused import --- .../main/java/org/avni/server/service/MetadataDiffChecker.java | 1 - 1 file changed, 1 deletion(-) diff --git a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java index 26adbe40c..224c15eab 100644 --- a/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java +++ b/avni-server-api/src/main/java/org/avni/server/service/MetadataDiffChecker.java @@ -1,6 +1,5 @@ package org.avni.server.service; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.*;