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