Fix for Penetration test _ Session and cookie management
[vid.git] / vid-app-common / src / main / java / org / onap / vid / services / CsvServiceImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * VID
4  * ================================================================================
5  * Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.vid.services;
22
23 import static org.apache.commons.lang3.exception.ExceptionUtils.rethrow;
24 import static org.onap.vid.utils.Logging.getMethodName;
25
26 import com.opencsv.CSVReader;
27 import java.io.FileReader;
28 import java.io.IOException;
29 import java.io.InputStreamReader;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.List;
33 import javax.ws.rs.BadRequestException;
34 import org.json.JSONArray;
35 import org.json.JSONObject;
36 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
37 import org.springframework.stereotype.Service;
38 import org.springframework.web.multipart.MultipartFile;
39
40 @Service
41 public class CsvServiceImpl implements CsvService{
42
43
44     /** The logger. */
45     static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(CsvServiceImpl.class);
46
47     private static final String ARRAY_REGEX = "\\[(.*?)\\]";
48
49
50     /**
51      * In UTF-8 the first line starts with "\uFEFF" so need to remove it
52      * @param line is first line contains BOM
53      * @return line after change
54      */
55     private String [] removeBOMFromCsv(String [] line){
56         if (line.length>0)
57             line[0] = line[0].replaceFirst("\uFEFF","").replaceFirst("","");
58         return line;
59     }
60
61     /**
62      * read a csv file and puts its content in list of string arrays (without the empty lines)
63      * @param filePath - the path of file to read
64      * @return the content of file
65      * @throws IOException
66      */
67     @Override
68     public List<String[]> readCsv(String filePath) throws IOException {
69         CSVReader reader = new CSVReader(new FileReader(filePath));
70         return readCsv(reader);
71     }
72
73     @Override
74     public List<String[]> readCsv(MultipartFile file) throws IOException {
75         CSVReader reader = new CSVReader(new InputStreamReader(file.getInputStream()));
76         return readCsv(reader);
77     }
78
79     private List<String[]> addLineWithoutSpaces(List<String[]> myEntries, String [] line){
80         line = Arrays.stream(line).filter(x -> !"".equals(x)).toArray(String[]::new);
81         if(line.length > 0)
82             myEntries.add(line);
83         return myEntries;
84     }
85
86
87     private  List<String[]> readCsv(CSVReader reader) {
88         try {
89             List<String[]> myEntries = new ArrayList<>() ;
90             String [] line;
91             Boolean firstLine = true;
92             while ((line = reader.readNext())!= null) {
93                 if (firstLine) {
94                     line = removeBOMFromCsv(line);
95                     firstLine = false;
96                 }
97                 myEntries = addLineWithoutSpaces(myEntries, line);
98             }
99             return myEntries;
100         }
101         catch (Exception e){
102             logger.error("error during reading CSV file. exception:" + e.getMessage());
103             return rethrow(e);
104         }
105
106     }
107
108     /**
109      * main function that call to the recursive function with initial parameters
110      * @param myEntries - the matrix with file content
111      * @return the json
112      * @throws IOException
113      * @throws InstantiationException
114      * @throws IllegalAccessException
115      */
116     @Override
117     public JSONObject convertCsvToJson (List<String[]> myEntries) throws InstantiationException, IllegalAccessException {
118         try {
119             return buildJSON(myEntries, 0, 0, myEntries.size(), JSONObject.class);
120         }
121         catch (Exception e){
122             logger.error("error during parsing CSV file. exception:" + e.getMessage());
123             throw e;
124         }
125
126     }
127
128     /**
129      * it goes over the matrix column while the values are the same and returns the index of changed value
130      * @param myEntries the matrix
131      * @param i row index refer to the whole matrix
132      * @param j column index
133      * @param numLines the length of the current inner matrix
134      * @param startLine row index of inner matrix
135      * @return the index of changed line
136      */
137     private int findIndexOfChangedLine(List<String[]> myEntries, final int i, final int j, final int numLines, final int startLine) {
138         int k;
139         for(k = 0; k + i - startLine < numLines && myEntries.get(i)[j].equals(myEntries.get(k + i)[j]) ; k++);
140         return k;
141     }
142
143     /**
144      *  check in array if its first element or if the key already exist in the previous item
145      * @param jsonArray - the array to search in
146      * @param key - the key to check
147      * @return if exists or first element return true, otherwise- false
148      */
149     private Boolean keyExistsOrFirstElement( JSONArray jsonArray,String key){
150         Boolean exists = false;
151         Boolean first = false;
152         JSONObject lastItem = lastItemInArray(jsonArray);
153         if (lastItem == null) {
154             first = true;
155         }
156         else {
157             if (lastItem.has(key)) {
158                 exists = true;
159             }
160         }
161         return exists||first;
162     }
163
164     /**
165      * return last json in json array
166      * @param jsonArray
167      * @return last item or null if the array is empty
168      */
169     private JSONObject lastItemInArray(JSONArray jsonArray){
170         JSONObject lastItem = null;
171         if(jsonArray.length()>0) {
172             lastItem = (JSONObject) jsonArray.get(jsonArray.length() - 1);
173         }
174         return lastItem;
175     }
176
177     /**
178      * append current json to the main json
179      * @param json - the main json to append to it
180      * @param key - key to append
181      * @param values - value(s) to append
182      * @param <T> can be JSONObject or JSONArray
183      * @param <E> string or jsonObject or jsonArray
184      * @return json after put
185      * @throws IllegalAccessException
186      * @throws InstantiationException
187      */
188     private <T, E> T putJson(T json, String key, E values) {
189         if (json instanceof JSONArray){
190             JSONArray currentJson= ((JSONArray)json);
191             if (values == null) //array of strings (for last item)
192             {
193                 currentJson.put(key);
194             }
195             else {
196                 if (keyExistsOrFirstElement(currentJson, key)) {
197                     currentJson.put(new JSONObject().put(key, values));
198                 } else {
199                 JSONObject lastItem = lastItemInArray(currentJson);
200                     if(lastItem != null) {
201                         lastItem.put(key, values);
202                     }
203                 }
204             }
205         }
206         if (json instanceof JSONObject){
207             if (values == null)
208                 throw new BadRequestException("Invalid csv file");
209             ((JSONObject)json).put(key,values);
210         }
211         return json;
212     }
213
214
215     /**
216      *  recursive function to build JSON. Each time it counts the same values in left and send the smaller matrix
217      *  (until the changed value) to the next time.
218      *
219      * @param myEntries - the whole matrix
220      * @param i- row index of the whole matrix
221      * @param j - column index
222      * @param numLines - number of lines of inner matrix (num of same values in the left column)
223      * @param clazz JSONArray or JSONObject
224      * @param <T> JSONArray or JSONObject
225      * @return the json object
226      * @throws IllegalAccessException
227      * @throws InstantiationException
228      */
229     private <T> T buildJSON(List<String[]> myEntries, int i, final int j, final int numLines, Class<T> clazz) throws IllegalAccessException, InstantiationException {
230         logger.debug(EELFLoggerDelegate.debugLogger, "start {}({}, {}, {})", getMethodName(), i, j, numLines);
231         T json = clazz.newInstance();
232         int startLine = i;
233         while(i < numLines + startLine){
234             String[] currentRow = myEntries.get(i);
235             int length = currentRow.length;
236             int currentDuplicateRows = findIndexOfChangedLine(myEntries,i,j,numLines, startLine);
237             String key = currentRow[j];
238             if (j == length-1) {
239                 json = putJson(json,currentRow[j],null);
240             }
241             else
242             {
243                 json = buildJsonRow(myEntries, i, j, json, currentRow, length, currentDuplicateRows, key);
244             }
245             i += currentDuplicateRows;
246         }
247         logger.debug(EELFLoggerDelegate.debugLogger, "end {} json = {}", getMethodName(), json);
248         return json;
249     }
250
251     private <T> T buildJsonRow(List<String[]> myEntries, int i, int j, T json, String[] currentRow, int length, int currentDuplicateRows, String key) throws IllegalAccessException, InstantiationException {
252         if (key.matches(ARRAY_REGEX)){
253             JSONArray arrayObjects = buildJSON(myEntries, i, j + 1, currentDuplicateRows, JSONArray.class);
254             json = putJson(json,key.replaceAll("\\[","").replaceAll("]",""),arrayObjects);
255         }
256         else {
257             if (j < length - 2) {
258                 json = putJson(json, currentRow[j], buildJSON(myEntries, i, j + 1, currentDuplicateRows, JSONObject.class));
259             }
260             else
261             {
262                 if (j == length - 2)//last object
263                 {
264                     if(currentDuplicateRows > 1) {
265                         throw new BadRequestException("Invalid csv file");
266                     }
267                     json = putJson(json, currentRow[j], currentRow[j + 1]);
268                 }
269             }
270         }
271         return json;
272     }
273
274 }
275