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