2 * Copyright 2017 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.utils;
19 import static org.onap.cli.fw.conf.OnapCommandConstants.ATTRIBUTES;
20 import static org.onap.cli.fw.conf.OnapCommandConstants.DEAFULT_INPUT_PARAMETERS_NAME;
21 import static org.onap.cli.fw.conf.OnapCommandConstants.DEFAULT_SCHEMA_PATH_PATERN;
22 import static org.onap.cli.fw.conf.OnapCommandConstants.DESCRIPTION;
23 import static org.onap.cli.fw.conf.OnapCommandConstants.DISCOVERY_FILE;
24 import static org.onap.cli.fw.conf.OnapCommandConstants.IS_DEFAULT_PARAM;
25 import static org.onap.cli.fw.conf.OnapCommandConstants.NAME;
26 import static org.onap.cli.fw.conf.OnapCommandConstants.OPEN_CLI_SAMPLE_VERSION;
27 import static org.onap.cli.fw.conf.OnapCommandConstants.OPEN_CLI_SCHEMA_VERSION;
28 import static org.onap.cli.fw.conf.OnapCommandConstants.PARAMETERS;
29 import static org.onap.cli.fw.conf.OnapCommandConstants.RESULTS;
30 import static org.onap.cli.fw.conf.OnapCommandConstants.SCHEMA_DIRECTORY;
31 import static org.onap.cli.fw.conf.OnapCommandConstants.SCHEMA_PATH_PATERN;
34 import java.io.IOException;
35 import java.lang.reflect.Constructor;
36 import java.lang.reflect.InvocationTargetException;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.HashMap;
40 import java.util.List;
42 import java.util.Optional;
43 import java.util.ServiceLoader;
45 import org.apache.commons.io.FileUtils;
46 import org.onap.cli.fw.cmd.OnapCommand;
47 import org.onap.cli.fw.conf.OnapCommandConfig;
48 import org.onap.cli.fw.conf.OnapCommandConstants;
49 import org.onap.cli.fw.error.OnapCommandDiscoveryFailed;
50 import org.onap.cli.fw.error.OnapCommandException;
51 import org.onap.cli.fw.error.OnapCommandInstantiationFailed;
52 import org.onap.cli.fw.error.OnapCommandInvalidSample;
53 import org.onap.cli.fw.error.OnapCommandInvalidSchema;
54 import org.onap.cli.fw.error.OnapCommandNotFound;
55 import org.onap.cli.fw.schema.OnapCommandSchemaInfo;
56 import org.springframework.core.io.Resource;
57 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
58 import org.springframework.core.io.support.ResourcePatternResolver;
59 import com.esotericsoftware.yamlbeans.YamlReader;
60 import com.google.gson.Gson;
61 import com.google.gson.GsonBuilder;
62 import com.google.gson.stream.JsonReader;
63 import java.io.FileReader;
64 import java.io.Writer;
65 import java.io.FileWriter;
66 import java.io.InputStream;
67 import java.io.InputStreamReader;
68 import java.io.FileInputStream;
70 public class OnapCommandDiscoveryUtils {
71 private OnapCommandDiscoveryUtils() {
72 throw new IllegalStateException("Utility class");
75 private static Gson gson = new GsonBuilder().serializeNulls().create();
78 * Fetch a particular schema details.
82 * @return ExternalSchema obj
83 * @throws OnapCommandInvalidSchema
85 * @throws OnapCommandDiscoveryFailed
88 public static OnapCommandSchemaInfo getSchemaInfo(String cmd, String version) throws OnapCommandException {
89 List<OnapCommandSchemaInfo> list = OnapCommandDiscoveryUtils.discoverOrLoadSchemas(false);
90 OnapCommandSchemaInfo schemaInfo = null;
91 if (list != null) { //NOSONAR
92 for (OnapCommandSchemaInfo schema : list) {
93 if (cmd.equals(schema.getCmdName()) && version.equals(schema.getProduct())) {
100 if (schemaInfo == null)
101 throw new OnapCommandNotFound(cmd, version);
107 * Load the previous discovered json file.
110 * @throws OnapCommandInvalidSchema
112 * @throws OnapCommandDiscoveryFailed
115 public static List<OnapCommandSchemaInfo> discoverOrLoadSchemas(boolean forceRefresh) throws OnapCommandException {
116 List<OnapCommandSchemaInfo> schemas = new ArrayList<>(); //NOSONAR
117 if (forceRefresh || Boolean.parseBoolean(OnapCommandConfig.getPropertyValue(OnapCommandConstants.DISCOVER_ALWAYS))
118 || !OnapCommandDiscoveryUtils.isAlreadyDiscovered()) {
119 schemas = OnapCommandDiscoveryUtils.discoverSchemas();
120 if (!schemas.isEmpty()) {
121 //merge the existing RPC schema with discovered ones
122 List<OnapCommandSchemaInfo> schemasExisting = OnapCommandDiscoveryUtils.loadSchemas();
124 Map<String, OnapCommandSchemaInfo> rpcCommands = new HashMap<>();
125 for (OnapCommandSchemaInfo info: schemasExisting) {
127 rpcCommands.put(info.getProduct() + ":" + info.getCmdName(), info);
131 //mrkanag: Enable clustering for keeping command in more than one OCLIP engine
132 //Remove if already an same command exists with RPC
133 for (OnapCommandSchemaInfo info: schemas) {
134 OnapCommandSchemaInfo infoExisting = rpcCommands.get(info.getProduct() + ":" + info.getCmdName());
135 if (infoExisting != null) {
136 rpcCommands.remove(info.getProduct() + ":" + info.getCmdName());
141 schemas.addAll(rpcCommands.values());
143 OnapCommandDiscoveryUtils.persistSchemaInfo(schemas);
146 schemas = OnapCommandDiscoveryUtils.loadSchemas();
152 public static String getDataStorePath() {
153 return OnapCommandConfig.getPropertyValue(OnapCommandConstants.OPEN_CLI_DATA_DIR);
156 public static List<OnapCommandSchemaInfo> loadSchemas() throws OnapCommandException {
157 List<OnapCommandSchemaInfo> schemas = new ArrayList<>();
159 if (!OnapCommandDiscoveryUtils.isAlreadyDiscovered()) return schemas;
161 String dataDir = OnapCommandDiscoveryUtils.getDataStorePath();
162 File file = new File(dataDir + File.separator + DISCOVERY_FILE);
163 try (JsonReader jsonReader = new JsonReader(new FileReader(file))){
164 OnapCommandSchemaInfo[] list = gson.fromJson(jsonReader, OnapCommandSchemaInfo[].class);
165 schemas.addAll(Arrays.asList(list));
166 } catch (Exception e) { // NOSONAR
167 throw new OnapCommandDiscoveryFailed(dataDir,
175 * Check if json file discovered or not.
178 * @throws OnapCommandDiscoveryFailed
181 public static boolean isAlreadyDiscovered() throws OnapCommandDiscoveryFailed { //NOSONAR
182 String dataDir = OnapCommandDiscoveryUtils.getDataStorePath();
183 return new File(dataDir + File.separator + DISCOVERY_FILE).exists();
187 * Persist the external schema details.
191 * @throws OnapCommandDiscoveryFailed
194 public static void persistSchemaInfo(List<OnapCommandSchemaInfo> schemas) throws OnapCommandDiscoveryFailed {
195 if (schemas != null) {
196 String dataDir = OnapCommandDiscoveryUtils.getDataStorePath();
199 FileUtils.forceMkdir(new File(dataDir));
201 File file = new File(dataDir + File.separator + DISCOVERY_FILE);
202 try(Writer writer = new FileWriter(file)){
203 gson.toJson(schemas,writer);
205 } catch (Exception e1) { // NOSONAR
206 throw new OnapCommandDiscoveryFailed(dataDir,
218 * @throws OnapCommandInvalidSchema
221 public static Map<String, Object> loadSchema(Resource resource) throws OnapCommandInvalidSchema {
222 return loadYaml(resource);
226 * Returns a resource available under certain directory in class-path.
230 * @return found resource
231 * @throws IOException
234 public static Resource findResource(String fileName, String pattern) throws IOException {
235 Resource[] resources = OnapCommandDiscoveryUtils.findResources(pattern);
236 if (resources != null && resources.length > 0) { //NOSONAR
237 for (Resource res : resources) {
238 if ((res.getFilename() != null) && (res.getFilename().equals(fileName))) {
248 * Returns all resources available under certain directory in class-path.
252 * @return resources found resources
253 * @throws IOException
256 public static Resource[] findResources(String pattern) throws IOException {
257 ClassLoader cl = OnapCommandUtils.class.getClassLoader();
258 ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(cl);
259 return resolver.getResources("classpath*:" + pattern);
262 public static String identitySchemaProfileType(Map<String, ?> schemaYamlMap) {
264 for (String schemeType : OnapCommandConfig.getCommaSeparatedList(OnapCommandConstants.SCHEMA_TYPES_SUPPORTED)) {
265 if (schemaYamlMap.get(schemeType) != null) {
270 return OnapCommandConstants.BASIC_SCHEMA_PROFILE;
274 * Find external schema files.
276 * @return list ExternalSchema
277 * @throws OnapCommandDiscoveryFailed
279 * @throws OnapCommandInvalidSchema
282 public static List<OnapCommandSchemaInfo> discoverSchemas() throws OnapCommandException {
283 List<OnapCommandSchemaInfo> extSchemas = new ArrayList<>();
285 //collect default input parameters for every profile
286 Resource[] deafultRres = findResources(DEFAULT_SCHEMA_PATH_PATERN);
287 Map <String, List<Object>> defaultInputs = new HashMap<>();
289 if (deafultRres != null && deafultRres.length > 0) {
290 Map<String, ?> deafultResourceMap;
292 for (Resource resource : deafultRres) {
293 deafultResourceMap = loadYaml(resource, true);
295 if (deafultResourceMap != null && deafultResourceMap.size() > 0) {
296 //default_input_parameters_http.yaml
297 String profileName = resource.getFilename().substring(
298 DEAFULT_INPUT_PARAMETERS_NAME.length() + 1,
299 resource.getFilename().indexOf('.'));
300 if (deafultResourceMap.containsKey(PARAMETERS)) {
301 List<Object> params = new ArrayList<>();
302 for (Map<String, ?> p: (List<Map<String, ?>>) deafultResourceMap.get(PARAMETERS)) {
303 if (p.keySet().contains(IS_DEFAULT_PARAM) && ! (Boolean.getBoolean(String.valueOf(p.get(IS_DEFAULT_PARAM))))) {
308 defaultInputs.put(profileName, params);
314 Resource[] res = findResources(SCHEMA_PATH_PATERN);
315 if (res != null && res.length > 0) {
316 for (Resource resource : res) {
317 Map<String, ?> resourceMap;
319 resourceMap = loadYaml(resource);
320 } catch (OnapCommandException e) {
321 String resourceURI = resource.getURI().toString();
322 OnapCommandUtils.log.error("Ignores invalid schema {} {}", resourceURI, e);
326 if (resourceMap != null && resourceMap.size() > 0) {
327 OnapCommandSchemaInfo schema = new OnapCommandSchemaInfo();
329 schema.setSchemaURI(resource.getURI().toString());
331 Object obj = resourceMap.get(OPEN_CLI_SCHEMA_VERSION);
333 String schemaURI = schema.getSchemaURI();
334 OnapCommandUtils.log.info("Invalid Schema yaml {}", schemaURI);
337 schema.setVersion(obj.toString());
339 if (!schema.getVersion().equalsIgnoreCase(OnapCommandConstants.OPEN_CLI_SCHEMA_VERSION_VALUE_1_0)) {
340 String schemaURI = schema.getSchemaURI();
341 OnapCommandUtils.log.info("Unsupported Schema version found {} " + schemaURI);
345 //There are schema like default input parameters and does not have command name
346 if (resourceMap.get(NAME) != null) {
347 schema.setSchemaName(resource.getFilename());
348 schema.setCmdName((String) resourceMap.get(NAME));
350 schema.setDescription((String) resourceMap.get(DESCRIPTION));
352 Map<String, ?> infoMap = (Map<String, ?>) resourceMap.get(OnapCommandConstants.INFO);
353 if (infoMap != null && infoMap.get(OnapCommandConstants.INFO_TYPE) != null) {
354 schema.setType(infoMap.get(OnapCommandConstants.INFO_TYPE).toString());
357 if (infoMap != null && infoMap.get(OnapCommandConstants.INFO_PRODUCT) != null) {
358 schema.setProduct(infoMap.get(OnapCommandConstants.INFO_PRODUCT).toString());
361 if (infoMap != null && infoMap.get(OnapCommandConstants.INFO_IGNORE) != null) {
362 schema.setIgnore(infoMap.get(OnapCommandConstants.INFO_IGNORE).toString());
365 if (infoMap != null && infoMap.get(OnapCommandConstants.INFO_STATE) != null) {
366 schema.setState(infoMap.get(OnapCommandConstants.INFO_STATE).toString());
369 if (infoMap != null && infoMap.get(OnapCommandConstants.INFO_SERVICE) != null) {
370 schema.setService(infoMap.get(OnapCommandConstants.INFO_SERVICE).toString());
373 if (infoMap != null && infoMap.get(OnapCommandConstants.INFO_AUTHOR) != null) {
374 schema.setAuthor(infoMap.get(OnapCommandConstants.INFO_AUTHOR).toString());
377 if (infoMap != null && infoMap.get(OnapCommandConstants.INFO_METADATA) != null) {
378 schema.setMetadata((Map<String, String>)infoMap.get(OnapCommandConstants.INFO_METADATA));
381 schema.setSchemaProfile(identitySchemaProfileType(resourceMap));
383 if (resourceMap.containsKey(PARAMETERS)) {
384 schema.setInputs((List<Object>)resourceMap.get(PARAMETERS));
385 if (defaultInputs.get(schema.getSchemaProfile()) != null) {
386 schema.getInputs().addAll(defaultInputs.get(schema.getSchemaProfile()));
390 if (resourceMap.containsKey(RESULTS)) {
391 schema.setOutputs((List<Object>)((Map<String, Object>)resourceMap.get(RESULTS)).get(ATTRIBUTES));
394 extSchemas.add(schema);
401 } catch (IOException e) {
402 throw new OnapCommandDiscoveryFailed(SCHEMA_DIRECTORY, e);
406 Resource[] samples = findResources(OnapCommandConstants.VERIFY_SAMPLES_FILE_PATTERN);
407 for (Resource sample : samples) {
408 updateSchemaInfoWithSample(sample, extSchemas);
410 } catch (IOException e) {
411 throw new OnapCommandDiscoveryFailed(OnapCommandConstants.VERIFY_SAMPLES_DIRECTORY, e);
417 private static void updateSchemaInfoWithSample(Resource sampleResourse,
418 List<OnapCommandSchemaInfo> schemaInfos) throws OnapCommandInvalidSchema, IOException {
419 Map<String, ?> infoMap = loadSchema(sampleResourse);
421 if (infoMap == null) {
425 Object sampleVersion = infoMap.get(OPEN_CLI_SAMPLE_VERSION);
426 if (sampleVersion == null) {
427 OnapCommandUtils.log.info("Invalid Sample yaml {}", sampleResourse.getURI());
431 if (!sampleVersion.toString().equalsIgnoreCase(OnapCommandConstants.OPEN_CLI_SAMPLE_VERSION_VALUE_1_0)) {
432 OnapCommandUtils.log.info("Unsupported Sample version found {}", sampleResourse.getURI());
436 String cmdName = (String) infoMap.get(OnapCommandConstants.VERIFY_CMD_NAME);
437 String version = (String) infoMap.get(OnapCommandConstants.VERIFY_CMD_VERSION);
439 Optional<OnapCommandSchemaInfo> optSchemaInfo = schemaInfos.stream()
440 .filter(e -> e.getCmdName().equals(cmdName) && e.getProduct().equals(version))
443 if (optSchemaInfo.isPresent()) {
444 OnapCommandSchemaInfo onapCommandSchemaInfo = optSchemaInfo.get();
445 onapCommandSchemaInfo.getSampleFiles().add(sampleResourse.getFilename());
450 * Discover the Oclip commands.
454 public static List<Class<OnapCommand>> discoverCommandPlugins() {
455 ServiceLoader<OnapCommand> loader = ServiceLoader.load(OnapCommand.class);
456 List<Class<OnapCommand>> clss = new ArrayList<>();
457 for (OnapCommand implClass : loader) {
458 clss.add((Class<OnapCommand>) implClass.getClass());
465 * Instantiate command plugin
466 * @throws OnapCommandInstantiationFailed
468 public static OnapCommand loadCommandClass(Class <? extends OnapCommand> cls) throws OnapCommandInstantiationFailed {
470 Constructor<?> constr = cls.getConstructor();
471 return (OnapCommand) constr.newInstance();
472 } catch (NoSuchMethodException | SecurityException | InstantiationException
473 | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
474 throw new OnapCommandInstantiationFailed(cls.getName(), e);
479 public static List<Map<String, Object>> createTestSuite(String cmd, String version) throws OnapCommandException {
481 ArrayList<Map<String, Object>> testSamples = new ArrayList<>();
484 List<Resource> resources = new ArrayList<>();
485 OnapCommandSchemaInfo schemaInfo = getSchemaInfo(cmd, version);
487 List<String> sampleFiles = new ArrayList<>();
488 if (schemaInfo != null && !schemaInfo.getSampleFiles().isEmpty()) { //NOSONAR
489 sampleFiles.addAll(schemaInfo.getSampleFiles());
492 for (String sampleFile : sampleFiles) {
494 Resource resource = OnapCommandDiscoveryUtils.findResource(sampleFile,
495 OnapCommandConstants.VERIFY_SAMPLES_FILE_PATTERN);
496 resources.add(resource);
497 } catch (IOException e) {
498 throw new OnapCommandInvalidSample("Sample file does not exist : " + sampleFile , e);
502 for (Resource resource : resources) {
504 Map<String, ?> stringMap = OnapCommandDiscoveryUtils.loadYaml(resource);
505 Map<String, Map<String, String>> samples = (Map<String, Map<String, String>>) stringMap
506 .get(OnapCommandConstants.VERIFY_SAMPLES);
508 for (Map.Entry<String,Map<String, String>> entry : samples.entrySet()) {
509 String sampleId=entry.getKey();
510 Map<String, String> sample = entry.getValue();
512 List<String> inputArgs = new ArrayList<>();
513 if (sample.get(OnapCommandConstants.VERIFY_INPUT) != null) {
514 inputArgs.addAll(Arrays.asList(sample.get(OnapCommandConstants.VERIFY_INPUT).trim().split(" ")));
516 inputArgs.add(OnapCommandConstants.VERIFY_LONG_OPTION);
518 HashMap<String, Object> map = new HashMap<>();
519 map.put(OnapCommandConstants.VERIFY_INPUT, inputArgs);
520 map.put(OnapCommandConstants.VERIFY_OUPUT, sample.get(OnapCommandConstants.VERIFY_OUPUT));
521 map.put(OnapCommandConstants.VERIFY_MOCO, sample.get(OnapCommandConstants.VERIFY_MOCO));
522 map.put(OnapCommandConstants.VERIFY_SAMPLE_FILE_ID, resource.getFilename());
523 map.put(OnapCommandConstants.VERIFY_SAMPLE_ID, sampleId);
524 testSamples.add(map);
536 * @throws OnapCommandInvalidSchema
539 public static Map<String, Object> loadYaml(Resource resource) throws OnapCommandInvalidSchema {
540 Map<String, Object> values = null;
542 values = loadYaml(resource.getInputStream());
543 } catch (Exception e) {
544 throw new OnapCommandInvalidSchema(resource.getFilename(), e);
554 * ignoreInvalidSchema boolean
556 * @throws OnapCommandInvalidSchema
559 public static Map<String, ?> loadYaml(Resource resource, boolean ignoreInvalidSchema) throws OnapCommandInvalidSchema, IOException {
560 Map<String, ?> values = null;
562 values = loadYaml(resource.getInputStream());
563 } catch (OnapCommandException | IOException e) {
564 OnapCommandUtils.log.error("Ignores invalid schema {} {}", resource.getURI(), e);
574 * @throws OnapCommandInvalidSchema
577 public static Map<String, Object> loadYaml(String filePath) throws OnapCommandInvalidSchema {
578 Map<String, Object> values = null;
580 values = loadYaml(new FileInputStream(new File(filePath)));
581 } catch (Exception e) {
582 throw new OnapCommandInvalidSchema(filePath, e);
593 * @throws OnapCommandInvalidSchema
596 public static Map<String, Object> loadYaml(InputStream inputStream) throws OnapCommandInvalidSchema {
597 Map<String, Object> values = null;
598 try(InputStreamReader inputStreamReader = new InputStreamReader(inputStream);){
599 YamlReader reader = new YamlReader(inputStreamReader);
600 values = (Map<String, Object>) reader.read();
601 } catch (IOException e) {
602 throw new OnapCommandInvalidSchema(inputStream.getClass().getName(),e.getMessage());