Reduced code complexity
[cli.git] / framework / src / main / java / org / onap / cli / fw / store / OnapCommandArtifactStore.java
1 /*
2  * Copyright 2019 Huawei Technologies Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onap.cli.fw.store;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.nio.file.Files;
22 import java.nio.file.Paths;
23 import java.security.MessageDigest;
24 import java.security.NoSuchAlgorithmException;
25 import java.text.SimpleDateFormat;
26 import java.util.ArrayList;
27 import java.util.Date;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.Map;
32 import java.util.TimeZone;
33
34 import javax.xml.bind.DatatypeConverter;
35
36 import org.apache.commons.io.FileUtils;
37 import org.onap.cli.fw.conf.OnapCommandConfig;
38 import org.onap.cli.fw.conf.OnapCommandConstants;
39 import org.onap.cli.fw.error.OnapCommandArtifactAlreadyExist;
40 import org.onap.cli.fw.error.OnapCommandArtifactContentChecksumNotMatch;
41 import org.onap.cli.fw.error.OnapCommandArtifactContentNotExist;
42 import org.onap.cli.fw.error.OnapCommandArtifactNotFound;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 import com.google.gson.Gson;
47 import com.google.gson.GsonBuilder;
48 import com.google.gson.stream.JsonReader;
49 import java.io.FileReader;
50
51 public class OnapCommandArtifactStore {
52     private static Logger log = LoggerFactory.getLogger(OnapCommandArtifactStore.class);
53     private static Gson gson = new GsonBuilder().serializeNulls().create();
54
55     private static boolean storeReady = false; //NOSONAR
56
57     private SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US);
58
59     private static final String SEPARATOR = "__";
60
61     public static class Artifact {
62         private String name;
63         private String description;
64         private String categoty;
65         private String checksum;
66         private long size;
67         private String createAt;
68         private String lastUpdatedAt;
69         private String path;
70         private Map<String, String> metadata = new HashMap<>();
71         public String getName() {
72             return name;
73         }
74         public void setName(String name) {
75             this.name = name;
76         }
77         public String getChecksum() {
78             return checksum;
79         }
80         public void setChecksum(String checksum) {
81             this.checksum = checksum;
82         }
83
84         public String getDescription() {
85             return description;
86         }
87         public void setDescription(String description) {
88             this.description = description;
89         }
90         public String getCategoty() {
91             return categoty;
92         }
93         public void setCategoty(String categoty) {
94             this.categoty = categoty;
95         }
96
97         public long getSize() {
98             return size;
99         }
100         public void setSize(long l) {
101             this.size = l;
102         }
103         public String getCreateAt() {
104             return createAt;
105         }
106         public void setCreateAt(String createAt) {
107             this.createAt = createAt;
108         }
109         public String getLastUpdatedAt() {
110             return lastUpdatedAt;
111         }
112         public void setLastUpdatedAt(String lastUpdatedAt) {
113             this.lastUpdatedAt = lastUpdatedAt;
114         }
115         public String getPath() {
116             return path;
117         }
118         public void setPath(String path) {
119             this.path = path;
120         }
121         public Map<String, String> getMetadata() {
122             return metadata;
123         }
124         public void setMetadata(Map<String, String> metadata) {
125             this.metadata = metadata;
126         }
127
128     }
129    static {
130         try {
131             FileUtils.forceMkdir(new File(getBasePath()));
132             storeReady = true;
133         } catch (IOException e) {
134             log.error("Failed to create the data store results");
135         }
136     }
137
138     private static OnapCommandArtifactStore store = null;
139
140     private OnapCommandArtifactStore() {
141         this.dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
142     }
143
144     public static OnapCommandArtifactStore getStore() {
145         if (store == null) {
146             store = new OnapCommandArtifactStore();
147         }
148
149         return store;
150     }
151
152     private static String getBasePath() {
153         return OnapCommandConfig.getPropertyValue(OnapCommandConstants.OPEN_CLI_DATA_DIR) +
154                 File.separator + "artifacts";
155     }
156
157     private static String getArtifactPath(String name, String category) {
158         return getBasePath() + File.separator + name + SEPARATOR + category + ".json";
159     }
160
161     private String getChecksum(String storePath) throws IOException, NoSuchAlgorithmException {
162         byte[] b = Files.readAllBytes(Paths.get(storePath));
163         byte[] hash = MessageDigest.getInstance("MD5").digest(b); //NOSONAR
164         return DatatypeConverter.printHexBinary(hash);
165     }
166
167     public Artifact createArtifact(Artifact artifact) throws OnapCommandArtifactContentNotExist, OnapCommandArtifactAlreadyExist, OnapCommandArtifactContentChecksumNotMatch { //NOSONAR
168         if (!new File(artifact.getPath()).exists()) {
169             throw new OnapCommandArtifactContentNotExist(artifact.getPath());
170         }
171
172         String storePath = getArtifactPath(artifact.getName(), artifact.getCategoty());
173         File aFile = new File(storePath);
174         if (aFile.exists()) {
175             throw new OnapCommandArtifactAlreadyExist(artifact.getName(), artifact.getCategoty());
176         }
177
178         try {
179             String actual = this.getChecksum(artifact.getPath());
180             artifact.setChecksum(actual);
181
182             artifact.setSize(new File(artifact.getPath()).length() / 1024);
183
184             artifact.setCreateAt(dateFormatter.format(new Date()));
185             artifact.setLastUpdatedAt(artifact.getCreateAt());
186
187             FileUtils.writeStringToFile(new File(storePath), gson.toJson(artifact));
188         } catch (Exception e) { // NOSONAR
189             //It is expected that this never occurs
190             log.error("Failed to store the artifact at {}", storePath);
191         }
192
193         return artifact;
194     }
195
196     public Artifact getArtifact(String name, String category) throws OnapCommandArtifactNotFound {
197         String storePath = getArtifactPath(name, category);
198         File aFile = new File(storePath);
199         if (!aFile.exists()) {
200             throw new OnapCommandArtifactNotFound(name, category);
201         }
202
203         try {
204             return gson.fromJson(FileUtils.readFileToString(aFile), Artifact.class);
205         } catch (Exception e) { // NOSONAR
206             //It is expected that this never occurs
207             log.error("Failed to retrieve the artifact at {}", storePath);
208         }
209         return null;
210     }
211
212
213     public List<Artifact> listArtifact(String category, String namePattern) throws OnapCommandArtifactNotFound { //NOSONAR
214         List<Artifact> artifacts = new ArrayList<>();
215
216         String searchPattern = "";
217         if (namePattern != null && !namePattern.isEmpty()) {
218             searchPattern += namePattern;
219         } else {
220             searchPattern += "*";
221         }
222
223         searchPattern += SEPARATOR;
224
225         if (category != null && !category.isEmpty()) {
226             searchPattern += category;
227         } else {
228             searchPattern += "*";
229         }
230
231         searchPattern += ".json";
232
233         final String SP = searchPattern; //NOSONAR
234
235         for (File file: new File(getBasePath()).listFiles(/*new FilenameFilter() {
236             @Override
237             public boolean accept(File dir, String name) {
238                 return name.matches(SP);
239             }
240         }*/)) {
241             try (JsonReader jsonReader = new JsonReader(new FileReader(file))){
242                 artifacts.add(gson.fromJson(jsonReader, Artifact.class));
243             } catch (Exception e) { // NOSONAR
244                 //It is expected that this never occurs
245                 String fileAbsPath = file.getAbsolutePath();
246                 log.error("While seraching Failed to retrieve the artifact at {}", fileAbsPath);
247             }
248         }
249
250         return artifacts;
251     }
252
253     public void deleteArtifact(String name, String category) throws OnapCommandArtifactNotFound {
254         String storePath = getArtifactPath(name, category);
255         File aFile = new File(storePath);
256         if (!aFile.exists()) {
257             throw new OnapCommandArtifactNotFound(name, category);
258         }
259         try {
260             Files.delete(Paths.get(storePath));
261         } catch (IOException e) {
262             log.error("Failed to delete the artifact {}",  aFile.getAbsolutePath());
263         }
264     }
265
266     public Artifact updateArtifact(String name, String category, Artifact artifact) throws OnapCommandArtifactNotFound, OnapCommandArtifactContentNotExist, OnapCommandArtifactAlreadyExist {
267         Artifact existing = this.getArtifact(name, category);
268         String existingStorePath = getArtifactPath(name, category);
269
270         String newStorePath = getArtifactPath(artifact.getName(), artifact.getCategoty());
271         if ( !existingStorePath.equalsIgnoreCase(newStorePath) && new File(newStorePath).exists()) {
272             throw new OnapCommandArtifactAlreadyExist(artifact.getName(), artifact.getCategoty());
273         }
274
275         try {
276             if (artifact.getName() == null) {
277                 artifact.setName(existing.getName());
278             }
279
280             if (artifact.getDescription() == null) {
281                 artifact.setDescription(existing.getDescription());
282             }
283
284             if (artifact.getCategoty() == null) {
285                 artifact.setCategoty(existing.getCategoty());
286             }
287
288             if (artifact.getPath()!= null) {
289                 if (!new File(artifact.getPath()).exists()) {
290                     throw new OnapCommandArtifactContentNotExist(artifact.getPath());
291                 }
292                 String actual = this.getChecksum(artifact.getPath());
293                 if (!existing.getChecksum().equals(actual)) {
294                     artifact.setChecksum(actual);
295                     artifact.setSize(new File(artifact.getPath()).length() / 1024);
296                 }
297             } else {
298                 artifact.setPath(existing.getPath());
299             }
300
301             artifact.setCreateAt(existing.getCreateAt());
302             artifact.setLastUpdatedAt(dateFormatter.format(new Date()));
303             if (artifact.getMetadata().size() > 0) {
304                 //update to existing one
305                 for (Map.Entry<String, String> entry: artifact.getMetadata().entrySet()) {
306                     if (entry.getValue() == null || entry.getValue().isEmpty() || entry.getValue().equalsIgnoreCase("null")) {
307                         existing.getMetadata().remove(entry.getKey());
308                     } else
309                         existing.getMetadata().put(entry.getKey(), entry.getValue());
310                 }
311
312                 artifact.setMetadata(existing.getMetadata());
313             }
314
315             FileUtils.writeStringToFile(new File(newStorePath), gson.toJson(artifact));
316
317             if (!newStorePath.equalsIgnoreCase(existingStorePath)) {
318                 this.deleteArtifact(name, category);
319             }
320         } catch (Exception e) { // NOSONAR
321             //It is expected that this never occurs
322             log.error("Failed to update the artifact at {}", existingStorePath);
323         }
324         return artifact;
325     }
326 }