1 package org.onap.vid.services;
3 import com.opencsv.CSVReader;
4 import org.json.JSONArray;
5 import org.json.JSONObject;
6 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
7 import org.springframework.stereotype.Service;
8 import org.springframework.web.multipart.MultipartFile;
10 import javax.ws.rs.BadRequestException;
11 import java.io.FileNotFoundException;
12 import java.io.FileReader;
13 import java.io.IOException;
14 import java.io.InputStreamReader;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.List;
19 import static org.onap.vid.utils.Logging.getMethodName;
22 public class CsvServiceImpl implements CsvService{
26 static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(CsvServiceImpl.class);
28 private static final String arrayRegex = "\\[(.*?)\\]";
32 * In UTF-8 the first line starts with "\uFEFF" so need to remove it
33 * @param line is first line contains BOM
34 * @return line after change
36 private String [] removeBOMFromCsv(String [] line){
38 line[0] = line[0].replaceFirst("\uFEFF","").replaceFirst("","");
43 * read a csv file and puts its content in list of string arrays (without the empty lines)
44 * @param filePath - the path of file to read
45 * @return the content of file
49 public List<String[]> readCsv(String filePath) throws IOException {
50 CSVReader reader = new CSVReader(new FileReader(filePath));
51 return readCsv(reader);
55 public List<String[]> readCsv(MultipartFile file) throws IOException {
56 CSVReader reader = new CSVReader(new InputStreamReader(file.getInputStream()));
57 return readCsv(reader);
60 private List<String[]> addLineWithoutSpaces(List<String[]> myEntries, String [] line){
61 line = Arrays.stream(line).filter(x -> !"".equals(x)).toArray(String[]::new);
68 private List<String[]> readCsv(CSVReader reader) throws IOException {
70 List<String[]> myEntries = new ArrayList<>() ;
72 Boolean firstLine = true;
73 while ((line = reader.readNext())!= null) {
75 line = removeBOMFromCsv(line);
78 myEntries = addLineWithoutSpaces(myEntries, line);
83 logger.error("error during reading CSV file. exception:" + e.getMessage());
90 * main function that call to the recursive function with initial parameters
91 * @param myEntries - the matrix with file content
94 * @throws InstantiationException
95 * @throws IllegalAccessException
98 public JSONObject convertCsvToJson (List<String[]> myEntries) throws InstantiationException, IllegalAccessException {
100 return buildJSON(myEntries, 0, 0, myEntries.size(), JSONObject.class);
103 logger.error("error during parsing CSV file. exception:" + e.getMessage());
110 * it goes over the matrix column while the values are the same and returns the index of changed value
111 * @param myEntries the matrix
112 * @param i row index refer to the whole matrix
113 * @param j column index
114 * @param numLines the length of the current inner matrix
115 * @param startLine row index of inner matrix
116 * @return the index of changed line
118 private int findIndexOfChangedLine(List<String[]> myEntries, final int i, final int j, final int numLines, final int startLine) {
120 for(k = 0; k + i - startLine < numLines && myEntries.get(i)[j].equals(myEntries.get(k + i)[j]) ; k++);
125 * check in array if its first element or if the key already exist in the previous item
126 * @param jsonArray - the array to search in
127 * @param key - the key to check
128 * @return if exists or first element return true, otherwise- false
130 private Boolean keyExistsOrFirstElement( JSONArray jsonArray,String key){
131 Boolean exists = false;
132 Boolean first = false;
133 JSONObject lastItem = lastItemInArray(jsonArray);
134 if (lastItem == null) {
138 if (lastItem.has(key)) {
142 return exists||first;
146 * return last json in json array
148 * @return last item or null if the array is empty
150 private JSONObject lastItemInArray(JSONArray jsonArray){
151 JSONObject lastItem = null;
152 if(jsonArray.length()>0) {
153 lastItem = (JSONObject) jsonArray.get(jsonArray.length() - 1);
159 * append current json to the main json
160 * @param json - the main json to append to it
161 * @param key - key to append
162 * @param values - value(s) to append
163 * @param <T> can be JSONObject or JSONArray
164 * @param <E> string or jsonObject or jsonArray
165 * @return json after put
166 * @throws IllegalAccessException
167 * @throws InstantiationException
169 private <T, E> T putJson(T json, String key, E values) throws IllegalAccessException, InstantiationException {
170 if (json instanceof JSONArray){
171 JSONArray currentJson= ((JSONArray)json);
172 if (values == null) //array of strings (for last item)
174 currentJson.put(key);
177 if (keyExistsOrFirstElement(currentJson, key)) {
178 currentJson.put(new JSONObject().put(key, values));
180 JSONObject lastItem = lastItemInArray(currentJson);
181 lastItem.put(key, values);
185 if (json instanceof JSONObject){
187 throw new BadRequestException("Invalid csv file");
188 ((JSONObject)json).put(key,values);
195 * recursive function to build JSON. Each time it counts the same values in left and send the smaller matrix
196 * (until the changed value) to the next time.
198 * @param myEntries - the whole matrix
199 * @param i- row index of the whole matrix
200 * @param j - column index
201 * @param numLines - number of lines of inner matrix (num of same values in the left column)
202 * @param clazz JSONArray or JSONObject
203 * @param <T> JSONArray or JSONObject
204 * @return the json object
205 * @throws IllegalAccessException
206 * @throws InstantiationException
208 private <T> T buildJSON(List<String[]> myEntries, int i, final int j, final int numLines, Class<T> clazz) throws IllegalAccessException, InstantiationException {
209 logger.debug(EELFLoggerDelegate.debugLogger, "start {}({}, {}, {})", getMethodName(), i, j, numLines);
210 T json = clazz.newInstance();
212 while(i < numLines + startLine){
213 String[] currentRow = myEntries.get(i);
214 int length = currentRow.length;
215 int currentDuplicateRows = findIndexOfChangedLine(myEntries,i,j,numLines, startLine);
216 String key = currentRow[j];
218 json = putJson(json,currentRow[j],null);
223 if (key.matches(arrayRegex)){
224 JSONArray arrayObjects = buildJSON(myEntries, i, j + 1, currentDuplicateRows, JSONArray.class);
225 json = putJson(json,key.replaceAll("\\[","").replaceAll("]",""),arrayObjects);
228 if (j < length - 2) {
229 json = putJson(json, currentRow[j], buildJSON(myEntries, i, j + 1, currentDuplicateRows, JSONObject.class));
233 if (j == length - 2)//last object
235 if(currentDuplicateRows > 1) {
236 throw new BadRequestException("Invalid csv file");
238 json = putJson(json, currentRow[j], currentRow[j + 1]);
243 i += currentDuplicateRows;
245 logger.debug(EELFLoggerDelegate.debugLogger, "end {} json = {}", getMethodName(), json);