2 * Copyright 2019 Huawei Technologies Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.onap.cli.fw.store;
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;
32 import java.util.TimeZone;
34 import javax.xml.bind.DatatypeConverter;
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;
46 import com.google.gson.Gson;
47 import com.google.gson.GsonBuilder;
48 import com.google.gson.stream.JsonReader;
49 import java.io.FileReader;
51 public class OnapCommandArtifactStore {
52 private static Logger log = LoggerFactory.getLogger(OnapCommandArtifactStore.class);
53 private static Gson gson = new GsonBuilder().serializeNulls().create();
55 private static boolean storeReady = false; //NOSONAR
57 private SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US);
59 private static final String SEPARATOR = "__";
61 public static class Artifact {
63 private String description;
64 private String categoty;
65 private String checksum;
67 private String createAt;
68 private String lastUpdatedAt;
70 private Map<String, String> metadata = new HashMap<>();
71 public String getName() {
74 public void setName(String name) {
77 public String getChecksum() {
80 public void setChecksum(String checksum) {
81 this.checksum = checksum;
84 public String getDescription() {
87 public void setDescription(String description) {
88 this.description = description;
90 public String getCategoty() {
93 public void setCategoty(String categoty) {
94 this.categoty = categoty;
97 public long getSize() {
100 public void setSize(long l) {
103 public String getCreateAt() {
106 public void setCreateAt(String createAt) {
107 this.createAt = createAt;
109 public String getLastUpdatedAt() {
110 return lastUpdatedAt;
112 public void setLastUpdatedAt(String lastUpdatedAt) {
113 this.lastUpdatedAt = lastUpdatedAt;
115 public String getPath() {
118 public void setPath(String path) {
121 public Map<String, String> getMetadata() {
124 public void setMetadata(Map<String, String> metadata) {
125 this.metadata = metadata;
131 FileUtils.forceMkdir(new File(getBasePath()));
133 } catch (IOException e) {
134 log.error("Failed to create the data store results");
138 private static OnapCommandArtifactStore store = null;
140 private OnapCommandArtifactStore() {
141 this.dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
144 public static OnapCommandArtifactStore getStore() {
146 store = new OnapCommandArtifactStore();
152 private static String getBasePath() {
153 return OnapCommandConfig.getPropertyValue(OnapCommandConstants.OPEN_CLI_DATA_DIR) +
154 File.separator + "artifacts";
157 private static String getArtifactPath(String name, String category) {
158 return getBasePath() + File.separator + name + SEPARATOR + category + ".json";
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);
167 public Artifact createArtifact(Artifact artifact) throws OnapCommandArtifactContentNotExist, OnapCommandArtifactAlreadyExist, OnapCommandArtifactContentChecksumNotMatch { //NOSONAR
168 if (!new File(artifact.getPath()).exists()) {
169 throw new OnapCommandArtifactContentNotExist(artifact.getPath());
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());
179 String actual = this.getChecksum(artifact.getPath());
180 artifact.setChecksum(actual);
182 artifact.setSize(new File(artifact.getPath()).length() / 1024);
184 artifact.setCreateAt(dateFormatter.format(new Date()));
185 artifact.setLastUpdatedAt(artifact.getCreateAt());
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);
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);
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);
213 public List<Artifact> listArtifact(String category, String namePattern) throws OnapCommandArtifactNotFound { //NOSONAR
214 List<Artifact> artifacts = new ArrayList<>();
216 String searchPattern = "";
217 if (namePattern != null && !namePattern.isEmpty()) {
218 searchPattern += namePattern;
220 searchPattern += "*";
223 searchPattern += SEPARATOR;
225 if (category != null && !category.isEmpty()) {
226 searchPattern += category;
228 searchPattern += "*";
231 searchPattern += ".json";
233 final String SP = searchPattern; //NOSONAR
235 for (File file: new File(getBasePath()).listFiles(/*new FilenameFilter() {
237 public boolean accept(File dir, String name) {
238 return name.matches(SP);
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);
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);
260 Files.delete(Paths.get(storePath));
261 } catch (IOException e) {
262 log.error("Failed to delete the artifact {}", aFile.getAbsolutePath());
266 public Artifact setArtifact(Artifact artifact, Artifact existing) throws OnapCommandArtifactNotFound, OnapCommandArtifactContentNotExist, OnapCommandArtifactAlreadyExist, IOException, NoSuchAlgorithmException {
267 if (artifact.getName() == null) {
268 artifact.setName(existing.getName());
271 if (artifact.getDescription() == null) {
272 artifact.setDescription(existing.getDescription());
275 if (artifact.getCategoty() == null) {
276 artifact.setCategoty(existing.getCategoty());
279 if (artifact.getPath()!= null) {
280 if (!new File(artifact.getPath()).exists()) {
281 throw new OnapCommandArtifactContentNotExist(artifact.getPath());
283 String actual = this.getChecksum(artifact.getPath());
284 if (!existing.getChecksum().equals(actual)) {
285 artifact.setChecksum(actual);
286 artifact.setSize(new File(artifact.getPath()).length() / 1024);
289 artifact.setPath(existing.getPath());
292 artifact.setCreateAt(existing.getCreateAt());
293 artifact.setLastUpdatedAt(dateFormatter.format(new Date()));
297 public Artifact updateArtifact(String name, String category, Artifact artifact) throws OnapCommandArtifactNotFound, OnapCommandArtifactContentNotExist, OnapCommandArtifactAlreadyExist {
298 Artifact existing = this.getArtifact(name, category);
299 String existingStorePath = getArtifactPath(name, category);
301 String newStorePath = getArtifactPath(artifact.getName(), artifact.getCategoty());
302 if ( !existingStorePath.equalsIgnoreCase(newStorePath) && new File(newStorePath).exists()) {
303 throw new OnapCommandArtifactAlreadyExist(artifact.getName(), artifact.getCategoty());
307 artifact = setArtifact(artifact, existing);
308 if (artifact.getMetadata().size() > 0) {
309 //update to existing one
310 for (Map.Entry<String, String> entry: artifact.getMetadata().entrySet()) {
311 if (entry.getValue() == null || entry.getValue().isEmpty() || entry.getValue().equalsIgnoreCase("null")) {
312 existing.getMetadata().remove(entry.getKey());
314 existing.getMetadata().put(entry.getKey(), entry.getValue());
317 artifact.setMetadata(existing.getMetadata());
320 FileUtils.writeStringToFile(new File(newStorePath), gson.toJson(artifact));
322 if (!newStorePath.equalsIgnoreCase(existingStorePath)) {
323 this.deleteArtifact(name, category);
325 } catch (Exception e) { // NOSONAR
326 //It is expected that this never occurs
327 log.error("Failed to update the artifact at {}", existingStorePath);