Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ConfigDeserializer.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2020 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
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  */
19 package org.sleuthkit.autopsy.integrationtesting.config;
20 
21 import com.fasterxml.jackson.databind.JsonNode;
22 import com.fasterxml.jackson.databind.ObjectMapper;
23 import com.fasterxml.jackson.databind.type.CollectionType;
24 import com.google.gson.Gson;
25 import com.google.gson.GsonBuilder;
26 import com.google.gson.JsonElement;
27 import java.io.File;
28 import java.io.IOException;
29 import java.lang.reflect.Type;
30 import java.util.Arrays;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.logging.Level;
38 import java.util.stream.Collectors;
39 import java.util.stream.IntStream;
40 import org.apache.commons.io.FileUtils;
41 import org.apache.commons.lang.StringUtils;
42 import org.apache.commons.collections.CollectionUtils;
44 
48 public class ConfigDeserializer {
49 
50  private static final String JSON_EXT = "json";
51  private static final Logger logger = Logger.getLogger(ConfigDeserializer.class.getName());
52  private static final ObjectMapper mapper = new ObjectMapper();
53 
54  // The following are the keys that must be provided as arguments (prefixed with 'integration-test.')
55  // A config file key must be specifed or at least the test suites path, and output path.
56  // If a config specifying the EnvConfig json exists, specify this path to load it
57  private static final String CONFIG_FILE_KEY = "configFile";
58  // expecting properties are marked as "integration-test.propVal"
59  private static final String INTEGRATION_TEST_NAMESPACE = "integration-test";
60 
72  public EnvConfig getEnvConfigFromSysProps() throws IOException, IllegalStateException {
73  String configFileKey = String.join(".", INTEGRATION_TEST_NAMESPACE, CONFIG_FILE_KEY);
74  if (System.getProperty(configFileKey) != null) {
75  // try to load from file if value is present
76  String fileLoc = System.getProperty(configFileKey);
77  File envConfigFile = new File(fileLoc);
78  if (envConfigFile.exists()) {
79  return getEnvConfig(envConfigFile);
80  } else {
81  throw new IllegalStateException(String.format("No file exists at %s", fileLoc));
82  }
83  } else {
84  // otherwise, try to load from properties
85  try {
86  Map<String, Object> integrationProperties = getOrCreate(getSysPropsMap(), INTEGRATION_TEST_NAMESPACE);
87  return validate(null, convertToObj(integrationProperties, EnvConfig.class));
88  } catch (IllegalStateException ex) {
89  throw new IllegalStateException("EnvConfig could not be determined from system property values", ex);
90  }
91  }
92  }
93 
102  private Map<String, Object> getSysPropsMap() {
103  Map<String, Object> mapToRet = new HashMap<>();
104 
105  for (String key : System.getProperties().stringPropertyNames()) {
106  String value = System.getProperty(key);
107 
108  String[] keyPieces = key.split("\\.");
109  Map<String, Object> mapToAddTo = mapToRet;
110  for (int i = 0; i < keyPieces.length - 1; i++) {
111  mapToAddTo = getOrCreate(mapToAddTo, keyPieces[i]);
112  }
113 
114  mapToAddTo.put(keyPieces[keyPieces.length - 1], value);
115  }
116 
117  return mapToRet;
118  }
119 
125  private static class StringObjMap extends HashMap<String, Object> {
126 
127  private static final long serialVersionUID = 1L;
128 
132  StringObjMap() {
133  }
134 
135  }
136 
145  private Map<String, Object> getOrCreate(Map<String, Object> parent, String key) {
146  Object child = parent.get(key);
147  if (child instanceof StringObjMap) {
148  return (StringObjMap) child;
149  } else {
150  Map<String, Object> toRet = new StringObjMap();
151  parent.put(key, toRet);
152  return toRet;
153  }
154  }
155 
164  public <T> T convertToObj(Map<String, Object> toConvert, Type clazz) {
165  GsonBuilder builder = new GsonBuilder();
166  Gson gson = builder.create();
167  JsonElement jsonElement = gson.toJsonTree(toConvert);
168  return gson.fromJson(jsonElement, clazz);
169  }
170 
180  public IntegrationTestConfig getIntegrationTestConfig() throws IOException, IllegalStateException {
181  EnvConfig envConfig = getEnvConfigFromSysProps();
182  String testSuiteConfigPath = PathUtil.getAbsolutePath(envConfig.getWorkingDirectory(), envConfig.getRootTestSuitesPath());
183 
184  return new IntegrationTestConfig(
185  getTestSuiteConfigs(new File(testSuiteConfigPath)),
186  envConfig
187  );
188  }
189 
198  public EnvConfig getEnvConfig(File envConfigFile) throws IOException, IllegalStateException {
199  EnvConfig config = mapper.readValue(envConfigFile, EnvConfig.class);
200  return validate(envConfigFile, config);
201  }
202 
212  private EnvConfig validate(File envConfigFile, EnvConfig config) throws IllegalStateException {
213  // set working directory based off of parent of envConfigFile if that parent exists
214  if (config.getWorkingDirectory() == null && envConfigFile != null && envConfigFile.getParentFile() != null) {
215  config.setWorkingDirectory(envConfigFile.getParentFile().getAbsolutePath());
216  }
217 
218  // env config should be non-null after validation
219  if (config == null
220  || StringUtils.isBlank(config.getRootCaseOutputPath())
221  || StringUtils.isBlank(config.getRootTestOutputPath())) {
222  throw new IllegalStateException("EnvConfig must have the root case output path and the root test output path set.");
223  }
224 
225  return config;
226  }
227 
238  public List<TestSuiteConfig> getTestSuiteConfig(File rootDirectory, File configFile) {
239  try {
240  JsonNode root = mapper.readTree(configFile);
241  if (root.isArray()) {
242  // Define a collection type of List<TestSuiteConfig> for the purposes of json deserialization.
243  CollectionType listClass = mapper.getTypeFactory().constructCollectionType(List.class,
244  TestSuiteConfig.class
245  );
246 
247  // This suppresses compiler warning for this cast.
248  @SuppressWarnings("unchecked")
249  List<TestSuiteConfig> testSuites = (List<TestSuiteConfig>) mapper.readValue(mapper.treeAsTokens(root), listClass);
250 
251  return validate(rootDirectory, configFile, testSuites);
252  } else {
253  return validate(rootDirectory, configFile, Arrays.asList(mapper.treeToValue(root, TestSuiteConfig.class
254  )));
255  }
256  } catch (IOException ex) {
257  logger.log(Level.WARNING, "Unable to read test suite config at " + configFile.getPath(), ex);
258  return Collections.emptyList();
259  }
260  }
261 
270  public List<TestSuiteConfig> getTestSuiteConfigs(File fileOrDirectory) {
271  if (fileOrDirectory.isDirectory()) {
272  Collection<File> jsonFiles = FileUtils.listFiles(fileOrDirectory, new String[]{JSON_EXT}, true);
273  return jsonFiles.stream()
274  .flatMap((file) -> getTestSuiteConfig(fileOrDirectory, file).stream())
275  .collect(Collectors.toList());
276  } else if (fileOrDirectory.isFile()) {
277  return getTestSuiteConfig(fileOrDirectory, fileOrDirectory);
278  }
279 
280  logger.log(Level.WARNING, "Unable to read file at: {0}", fileOrDirectory);
281  return Collections.emptyList();
282  }
283 
295  private List<TestSuiteConfig> validate(File rootDirectory, File file, List<TestSuiteConfig> testSuites) {
296  return IntStream.range(0, testSuites.size())
297  .mapToObj(idx -> validate(rootDirectory, file, idx, testSuites.get(idx)))
298  .filter(c -> c != null)
299  .collect(Collectors.toList());
300  }
301 
316  private TestSuiteConfig validate(File rootDirectory, File file, int index, TestSuiteConfig config) {
317  if (config == null
318  || StringUtils.isBlank(config.getName())
319  || config.getCaseTypes() == null
320  || CollectionUtils.isEmpty(config.getDataSources())
321  || config.getIntegrationTests() == null) {
322 
323  logger.log(Level.WARNING, String.format("Item in %s at index %d must contain a valid 'name', 'caseTypes', 'dataSources', and 'integrationTests'", file.toString(), index));
324  return null;
325  }
326 
327  if (config.getRelativeOutputPath() == null) {
328  // taken from https://stackoverflow.com/questions/204784/how-to-construct-a-relative-path-in-java-from-two-absolute-paths-or-urls
329  String relative = rootDirectory.toURI().relativize(file.toURI()).getPath();
330  if (relative.endsWith("." + JSON_EXT)) {
331  relative = relative.substring(0, relative.length() - ("." + JSON_EXT).length());
332  }
333  config.setRelativeOutputPath(relative);
334  }
335 
336  return config;
337  }
338 }
List< TestSuiteConfig > validate(File rootDirectory, File file, List< TestSuiteConfig > testSuites)
EnvConfig validate(File envConfigFile, EnvConfig config)
static String getAbsolutePath(String workingDirectory, String relPath)
Definition: PathUtil.java:40
List< TestSuiteConfig > getTestSuiteConfigs(File fileOrDirectory)
List< TestSuiteConfig > getTestSuiteConfig(File rootDirectory, File configFile)
Map< String, Object > getOrCreate(Map< String, Object > parent, String key)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
TestSuiteConfig validate(File rootDirectory, File file, int index, TestSuiteConfig config)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.