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