Removed the use of deprecated "toString"
[cli.git] / framework / src / main / java / org / onap / cli / fw / registrar / OnapCommandRegistrar.java
1 /*
2  * Copyright 2017 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.registrar;
18
19 import java.io.IOException;
20 import java.nio.charset.Charset;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26
27 import org.apache.commons.io.IOUtils;
28 import org.onap.cli.fw.cmd.OnapCommand;
29 import org.onap.cli.fw.cmd.dummy.OnapCommandDummy;
30 import org.onap.cli.fw.conf.OnapCommandConfig;
31 import org.onap.cli.fw.conf.OnapCommandConstants;
32 import org.onap.cli.fw.error.OnapCommandException;
33 import org.onap.cli.fw.error.OnapCommandHelpFailed;
34 import org.onap.cli.fw.error.OnapCommandNotFound;
35 import org.onap.cli.fw.error.OnapCommandProductVersionInvalid;
36 import org.onap.cli.fw.error.OnapCommandRegistrationProductInfoMissing;
37 import org.onap.cli.fw.error.OnapUnsupportedSchemaProfile;
38 import org.onap.cli.fw.output.OnapCommandPrintDirection;
39 import org.onap.cli.fw.output.OnapCommandResult;
40 import org.onap.cli.fw.output.OnapCommandResultAttribute;
41 import org.onap.cli.fw.output.OnapCommandResultAttributeScope;
42 import org.onap.cli.fw.output.OnapCommandResultType;
43 import org.onap.cli.fw.schema.OnapCommandSchema;
44 import org.onap.cli.fw.schema.OnapCommandSchemaInfo;
45 import org.onap.cli.fw.store.OnapCommandProfileStore;
46 import org.onap.cli.fw.utils.OnapCommandDiscoveryUtils;
47 import org.onap.cli.fw.utils.OnapCommandHelperUtils;
48 import org.onap.cli.fw.utils.OnapCommandUtils;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52
53 /**
54  * Oclip Command registrar provides a common place, where every command would get registered automatically when its
55  * loaded into JVM.
56  *
57  */
58 public class OnapCommandRegistrar {
59
60     private static Logger log = LoggerFactory.getLogger(OnapCommandRegistrar.class);
61
62     private Map<String, Class<? extends OnapCommand>> registry = new HashMap<>();
63
64     private Map<String, Class<? extends OnapCommand>> registryProfilePlugins = new HashMap<>();
65
66     private Set<String> availableProductVersions = new HashSet<>();
67
68     private String enabledProductVersion = null;
69
70     private boolean isInteractiveMode = false;
71
72     private String host;
73
74     private int port;
75
76     private OnapCommandProfileStore paramCache = OnapCommandProfileStore.getInstance();
77
78     public boolean isInteractiveMode() {
79         return isInteractiveMode;
80     }
81
82     public void setInteractiveMode(boolean isInteractiveMode) {
83         this.isInteractiveMode = isInteractiveMode;
84     }
85
86     public Map<String, String> getParamCache() {
87         return this.getParamCache(this.getEnabledProductVersion());
88     }
89
90     public Map<String, String> getParamCache(String product) {
91         return paramCache.getParams(product);
92     }
93
94     public void addParamCache(String paramName, String paramValue) {
95         paramCache.add(this.getEnabledProductVersion(), paramName, paramValue);
96     }
97
98     public void removeParamCache(String paramName) {
99         paramCache.remove(this.getEnabledProductVersion(), paramName);
100     }
101
102     public void setProfile(String profileName, List<String> includes, List<String> excludes) throws OnapCommandException {
103         this.paramCache.setProfile(profileName);
104
105         for (String profile : includes) {
106             this.paramCache.includeProfile(profile);
107         }
108
109         for (String profile : excludes) {
110             this.paramCache.excludeProfile(profile);
111         }
112     }
113
114     public List<String> getUserProfiles() {
115         return paramCache.getProfiles();
116     }
117
118     private static OnapCommandRegistrar registrar = null;
119
120     /**
121      * Register the command into registrar and throws OnapInvalidCommandRegistration for invalid command.
122      *
123      * @param name Command Name
124      * @param cmd  Command Class
125      * @throws OnapCommandRegistrationProductInfoMissing
126      */
127     private void register(String name, String version, Class<? extends OnapCommand> cmd) throws OnapCommandRegistrationProductInfoMissing {
128         if (version == null || version.isEmpty()) {
129             throw new OnapCommandRegistrationProductInfoMissing(name);
130         }
131
132         this.registry.put(name + ":" + version, cmd);
133         log.info("REGISITER : {} : {} = {}", name, version, cmd.getCanonicalName());
134         this.availableProductVersions.add(version);
135
136     }
137
138     private void registerProfilePlugin(String profile, Class<? extends OnapCommand> cmd) {
139         this.registryProfilePlugins.put(profile, cmd);
140     }
141
142     private OnapCommandRegistrar() {
143         this.enabledProductVersion = System.getenv(OnapCommandConstants.OPEN_CLI_PRODUCT_IN_USE_ENV_NAME); //NOSONAR
144         if (this.enabledProductVersion == null) {
145             this.enabledProductVersion = OnapCommandConfig.getPropertyValue(OnapCommandConstants.OPEN_CLI_PRODUCT_NAME);
146         }
147     }
148
149     /**
150      * Get global registrar.
151      *
152      * @throws OnapCommandException exception
153      */
154     public static OnapCommandRegistrar getRegistrar() throws OnapCommandException {
155         if (registrar == null) {
156             registrar = new OnapCommandRegistrar();
157             registrar.autoDiscoverSchemas(true);
158         }
159
160         return registrar;
161     }
162
163     public void resync() throws OnapCommandException {
164         registrar.autoDiscoverSchemas(false);
165     }
166
167     /**
168      * Get the list of discovered commands by registrar.
169      *
170      * @return set
171      */
172     public Set<String> listCommands() {
173         return this.registry.keySet();
174     }
175
176     /**
177      * Get the list of discovered commands for a given product version in registrar.
178      *
179      * @return set
180      */
181     public Set<String> listCommandsForEnabledProductVersion() {
182         String version = this.getEnabledProductVersion();
183
184         Set<String> cmds = new HashSet<>();
185         if (!this.availableProductVersions.contains(version)) {
186             return cmds;
187         }
188
189         for (String cmd : this.registry.keySet()) {
190             if (cmd.split(":")[1].equalsIgnoreCase(version)) {
191                 cmds.add(cmd.split(":")[0]);
192             }
193         }
194         return cmds;
195     }
196
197     public Class<? extends OnapCommand> getProfilePlugin(String profile) throws OnapUnsupportedSchemaProfile {
198         if (!this.registryProfilePlugins.containsKey(profile)) {
199             throw new OnapUnsupportedSchemaProfile(profile);
200         }
201
202         return this.registryProfilePlugins.get(profile);
203     }
204
205     public Set<String> getAvailableProductVersions() {
206         return this.availableProductVersions;
207     }
208
209     public void setEnabledProductVersion(String version) throws OnapCommandProductVersionInvalid {
210         if (!this.availableProductVersions.contains(version)) {
211             throw new OnapCommandProductVersionInvalid(version, availableProductVersions);
212         }
213
214         this.enabledProductVersion = version;
215     }
216
217     public String getEnabledProductVersion() {
218         return this.enabledProductVersion;
219     }
220
221     /**
222      * Returns command details.
223      *
224      * @return map
225      * @throws OnapCommandException exception
226      */
227     public List<OnapCommandSchemaInfo> listCommandInfo() throws OnapCommandException {
228         return OnapCommandDiscoveryUtils.discoverSchemas();
229     }
230
231     /**
232      * Get the OnapCommand, which CLI main would use to find the command based on the command name.
233      *
234      * @param cmdName Name of command
235      * @return OnapCommand
236      * @throws OnapCommandException Exception
237      */
238     public OnapCommand get(String cmdName) throws OnapCommandException {
239         return this.get(cmdName, this.getEnabledProductVersion());
240     }
241
242     /**
243      * Get the OnapCommand, which CLI main would use to find the command based on the command name.
244      *
245      * @param cmdName Name of command
246      * @param version product version
247      * @return OnapCommand
248      * @throws OnapCommandException Exception
249      */
250     public OnapCommand get(String cmdName, String version) throws OnapCommandException {
251         Class<? extends OnapCommand> cls = registry.get(cmdName + ":" + version);
252         //mrkanag: Restrict auth/catalog type commands only available during devMode. in production
253         //don't expose the auth type and catalog type commands
254
255         if (cls == null) {
256             throw new OnapCommandNotFound(cmdName, version);
257         }
258
259         OnapCommand cmd = OnapCommandDiscoveryUtils.loadCommandClass(cls);
260
261         OnapCommandSchemaInfo info = OnapCommandDiscoveryUtils.getSchemaInfo(cmdName, version);
262
263         cmd.initializeSchema(info);
264
265         return cmd;
266     }
267
268     private Map<String, Class<OnapCommand>> autoDiscoverCommandPlugins() throws OnapCommandException {
269         List<Class<OnapCommand>> cmds = OnapCommandDiscoveryUtils.discoverCommandPlugins();
270         Map<String, Class<OnapCommand>> map = new HashMap<>();
271
272         for (Class<OnapCommand> cmd : cmds) {
273             if (cmd.isAnnotationPresent(OnapCommandSchema.class)) {
274                 OnapCommandSchema ano = cmd.getAnnotation(OnapCommandSchema.class);
275                 if (ano.schema() != null && !ano.schema().isEmpty()) {
276                     map.put(ano.schema(), cmd);
277                 } else if (ano.type() != null && !ano.type().isEmpty()) {
278                     this.registerProfilePlugin(ano.type(), cmd);
279                     map.put(ano.type(), cmd);
280                 } else {
281                     throw new OnapUnsupportedSchemaProfile(ano.schema());
282                 }
283             }
284         }
285
286         return map;
287     }
288
289     private void autoDiscoverSchemas(boolean refresh) throws OnapCommandException {
290         List<OnapCommandSchemaInfo> schemas = OnapCommandDiscoveryUtils.discoverOrLoadSchemas(refresh);
291
292         Map<String, Class<OnapCommand>> plugins = this.autoDiscoverCommandPlugins();
293
294         for (OnapCommandSchemaInfo schema : schemas) {
295             if (schema.isIgnore()) {
296                 log.info("Ignoring schema {}", schema.getSchemaURI());
297                 continue;
298             }
299
300             //First check if there is an specific plug-in exist, otherwise check for profile plug-in
301             if (schema.isRpc()) {
302                 //proxy the schema by using rpc schema, when the schema is marked with rpc
303                 this.register(schema.getCmdName(), schema.getProduct(), plugins.get("schema-rpc.yaml"));
304             } else if (plugins.containsKey(schema.getSchemaName())) {
305                 this.register(schema.getCmdName(), schema.getProduct(), plugins.get(schema.getSchemaName()));
306             } else if (plugins.containsKey(schema.getSchemaProfile())) {
307                 this.register(schema.getCmdName(), schema.getProduct(), plugins.get(schema.getSchemaProfile()));
308             } else {
309                 this.register(schema.getCmdName(), schema.getProduct(), OnapCommandDummy.class);
310             }
311         }
312     }
313
314     /**
315      * Helps to find the Oclip CLI version, could be used with --version or -v option.
316      *
317      * @return string
318      */
319     public String getVersion() {
320         String version = this.getClass().getPackage().getImplementationVersion();
321         if (version == null) {
322             version = OnapCommandConfig.getPropertyValue(OnapCommandConstants.OPEN_CLI_VERSION);
323         }
324
325         String buildTime = OnapCommandHelperUtils.findLastBuildTime();
326         if (buildTime != null && !buildTime.isEmpty()) {
327             buildTime = " [" + buildTime + "]";
328         } else {
329             buildTime = "";
330         }
331
332         String configuredProductVersion = this.getEnabledProductVersion();
333
334         String versionInfo = "";
335         try {
336             versionInfo = IOUtils.toString((this.getClass().getClassLoader().getResourceAsStream(OnapCommandConstants.VERSION_INFO)), (Charset) null);
337         } catch (IOException e) { // NOSONAR
338             //Never occurs
339         }
340
341         versionInfo = versionInfo.replaceAll(OnapCommandConstants.VERSION_INFO_PLACE_HOLDER_ENB_PRD_VER, configuredProductVersion);
342         versionInfo = versionInfo.replaceAll(OnapCommandConstants.VERSION_INFO_PLACE_HOLDER_AVL_PRD_VER, this.availableProductVersions.toString());
343         versionInfo = versionInfo.replaceAll(OnapCommandConstants.VERSION_INFO_PLACE_HOLDER_VERSION + "", version + buildTime);
344
345         return versionInfo;
346     }
347
348     /**
349      * Provides the help message in tabular format for all commands registered in this registrar.
350      *
351      * @return string
352      * @throws OnapCommandHelpFailed Help cmd failed
353      */
354     public String getHelp() throws OnapCommandHelpFailed {
355         return this.getHelp(false);
356     }
357
358     public String getHelpForEnabledProductVersion() throws OnapCommandHelpFailed {
359         return this.getHelp(true);
360     }
361
362     private String getHelp(boolean isEnabledProductVersionOnly) throws OnapCommandHelpFailed {
363         OnapCommandResult help = new OnapCommandResult();
364         help.setType(OnapCommandResultType.TABLE);
365         help.setPrintDirection(OnapCommandPrintDirection.LANDSCAPE);
366
367         OnapCommandResultAttribute attr = new OnapCommandResultAttribute();
368         attr.setName(OnapCommandConstants.NAME.toUpperCase());
369         attr.setDescription(OnapCommandConstants.DESCRIPTION);
370         attr.setScope(OnapCommandResultAttributeScope.SHORT);
371         help.getRecords().add(attr);
372
373         OnapCommandResultAttribute attrVer = new OnapCommandResultAttribute();
374         if (!isEnabledProductVersionOnly) {
375             attrVer.setName(OnapCommandConstants.INFO_PRODUCT.toUpperCase());
376             attrVer.setDescription(OnapCommandConstants.DESCRIPTION);
377             attrVer.setScope(OnapCommandResultAttributeScope.SHORT);
378             help.getRecords().add(attrVer);
379         }
380
381         OnapCommandResultAttribute attrSrv = new OnapCommandResultAttribute();
382         attrSrv.setName(OnapCommandConstants.INFO_SERVICE.toUpperCase());
383         attrSrv.setDescription(OnapCommandConstants.INFO_SERVICE);
384         attrSrv.setScope(OnapCommandResultAttributeScope.SHORT);
385         help.getRecords().add(attrSrv);
386
387         OnapCommandResultAttribute attrState = new OnapCommandResultAttribute();
388         attrState.setName(OnapCommandConstants.INFO_STATE.toUpperCase());
389         attrState.setDescription(OnapCommandConstants.INFO_STATE);
390         attrState.setScope(OnapCommandResultAttributeScope.SHORT);
391         help.getRecords().add(attrState);
392
393
394         OnapCommandResultAttribute attrDesc = new OnapCommandResultAttribute();
395         attrDesc.setName(OnapCommandConstants.DESCRIPTION.toUpperCase());
396         attrDesc.setDescription(OnapCommandConstants.DESCRIPTION);
397         attrDesc.setScope(OnapCommandResultAttributeScope.SHORT);
398         help.getRecords().add(attrDesc);
399
400         for (String cmdName : isEnabledProductVersionOnly ?
401                 OnapCommandUtils.sort(this.listCommandsForEnabledProductVersion()) :
402                     OnapCommandUtils.sort(this.listCommands())) {
403             OnapCommand cmd;
404             try {
405                 if (!isEnabledProductVersionOnly) {
406                     String[] cmdVer = cmdName.split(":");
407                     cmd = this.get(cmdVer[0], cmdVer[1]);
408                     attr.getValues().add(cmdVer[0]);
409                     attrVer.getValues().add(cmdVer[1]);
410                 } else {
411                     cmd = this.get(cmdName);
412                     attr.getValues().add(cmdName);
413                 }
414
415                 //don't expose system commands for user usage
416                 //if (cmd.getInfo().getCommandType().name().equalsIgnoreCase(OnapCommandType.SYSTEM.name())) {
417                 //    continue;
418                 //}
419
420                 attrSrv.getValues().add(cmd.getInfo().getService());
421                 attrDesc.getValues().add(cmd.getDescription());
422                 attrState.getValues().add(cmd.getInfo().getState().name());
423             } catch (OnapCommandException e) {
424                 throw new OnapCommandHelpFailed(e);
425             }
426         }
427
428         try {
429             return "\n\nCommands:\n" + help.print() + (isEnabledProductVersionOnly ? "" : "\n" + this.getVersion());
430         } catch (OnapCommandException e) {
431             throw new OnapCommandHelpFailed(e);
432         }
433     }
434
435     public List<Map<String, Object>> getTestSuite(String cmd, String product) throws OnapCommandException {
436         return OnapCommandDiscoveryUtils.createTestSuite(cmd, product);
437     }
438
439     public String getHost() {
440         return host;
441     }
442
443     public void setHost(String host) {
444         this.host = host;
445     }
446
447     public int getPort() {
448         return port;
449     }
450
451     public void setPort(int port) {
452         this.port = port;
453     }
454 }