e05e02c1495d662ad61a16b7cd7972ef234ec230
[policy/apex-pdp.git] / services / services-engine / src / main / java / org / onap / policy / apex / service / engine / main / ApexCommandLineArguments.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  * 
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  * 
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.apex.service.engine.main;
22
23 import java.io.File;
24 import java.io.PrintWriter;
25 import java.io.StringWriter;
26 import java.net.URL;
27 import java.util.Arrays;
28
29 import org.apache.commons.cli.CommandLine;
30 import org.apache.commons.cli.DefaultParser;
31 import org.apache.commons.cli.HelpFormatter;
32 import org.apache.commons.cli.Option;
33 import org.apache.commons.cli.Options;
34 import org.apache.commons.cli.ParseException;
35 import org.onap.policy.apex.model.basicmodel.concepts.ApexException;
36 import org.onap.policy.apex.model.basicmodel.concepts.ApexRuntimeException;
37 import org.onap.policy.common.utils.resources.ResourceUtils;
38 import org.onap.policy.common.utils.validation.ParameterValidationUtils;
39
40 /**
41  * This class reads and handles command line parameters for the Apex main program.
42  *
43  * @author Liam Fallon (liam.fallon@ericsson.com)
44  */
45 public class ApexCommandLineArguments {
46     // A system property holding the root directory for relative paths in the configuration file
47     public static final String RELATIVE_FILE_ROOT = "APEX_RELATIVE_FILE_ROOT";
48
49     // Recurring string constants
50     private static final String FILE_PREAMBLE = " file \"";
51     private static final int HELP_LINE_LENGTH = 120;
52
53     // Apache Commons CLI options
54     private final Options options;
55
56     // The command line options
57     private String modelFilePath = null;
58     private String configurationFilePath = null;
59     private String relativeFileRoot = null;
60
61     /**
62      * Construct the options for the CLI editor.
63      */
64     public ApexCommandLineArguments() {
65         //@formatter:off
66         options = new Options();
67         options.addOption(Option.builder("h")
68                 .longOpt("help")
69                 .desc("outputs the usage of this command")
70                 .required(false)
71                 .type(Boolean.class)
72                 .build());
73         options.addOption(Option.builder("v")
74                         .longOpt("version")
75                         .desc("outputs the version of Apex")
76                         .required(false)
77                         .type(Boolean.class)
78                         .build());
79         options.addOption(Option.builder("c")
80                         .longOpt("config-file")
81                         .desc("the full path to the configuration file to use, "
82                                         + "the configuration file must be a Json file "
83                                         + "containing the Apex configuration parameters")
84                         .hasArg()
85                         .argName("CONFIG_FILE")
86                         .required(false)
87                         .type(String.class)
88                         .build());
89         options.addOption(Option.builder("rfr")
90                         .longOpt("relative-file-root")
91                         .desc("the root file path for relative file paths specified in the Apex configuration file, "
92                                         + "defaults to the current directory from where Apex is executed")
93                         .hasArg()
94                         .argName(RELATIVE_FILE_ROOT)
95                         .required(false)
96                         .type(String.class)
97                         .build());
98         options.addOption(Option.builder("m").longOpt("model-file")
99                 .desc("the full path to the model file to use, if set it overrides the model file set in the "
100                         + "configuration file").hasArg().argName("MODEL_FILE")
101                 .required(false)
102                 .type(String.class).build());
103         //@formatter:on
104     }
105
106     /**
107      * Construct the options for the CLI editor and parse in the given arguments.
108      *
109      * @param args The command line arguments
110      */
111     public ApexCommandLineArguments(final String[] args) {
112         // Set up the options with the default constructor
113         this();
114
115         // Parse the arguments
116         try {
117             parse(args);
118         } catch (final ApexException e) {
119             throw new ApexRuntimeException("parse error on Apex parameters", e);
120         }
121     }
122
123     /**
124      * Parse the command line options.
125      *
126      * @param args The command line arguments
127      * @return a string with a message for help and version, or null if there is no message
128      * @throws ApexException on command argument errors
129      */
130     public String parse(final String[] args) throws ApexException {
131         // Clear all our arguments
132         setConfigurationFilePath(null);
133         setModelFilePath(null);
134
135         CommandLine commandLine = null;
136         try {
137             commandLine = new DefaultParser().parse(options, args);
138         } catch (final ParseException e) {
139             throw new ApexException("invalid command line arguments specified : " + e.getMessage());
140         }
141
142         // Arguments left over after Commons CLI does its stuff
143         final String[] remainingArgs = commandLine.getArgs();
144
145         if (remainingArgs.length > 0 && commandLine.hasOption('c') || remainingArgs.length > 1) {
146             throw new ApexException("too many command line arguments specified : " + Arrays.toString(args));
147         }
148
149         if (remainingArgs.length == 1) {
150             configurationFilePath = remainingArgs[0];
151         }
152
153         if (commandLine.hasOption('h')) {
154             return help(ApexMain.class.getName());
155         }
156
157         if (commandLine.hasOption('v')) {
158             return version();
159         }
160
161         if (commandLine.hasOption('c')) {
162             setConfigurationFilePath(commandLine.getOptionValue('c'));
163         }
164
165         if (commandLine.hasOption("rfr")) {
166             setRelativeFileRoot(commandLine.getOptionValue("rfr"));
167         } else {
168             setRelativeFileRoot(null);
169         }
170
171         if (commandLine.hasOption('m')) {
172             setModelFilePath(commandLine.getOptionValue('m'));
173         }
174
175         return null;
176     }
177
178     /**
179      * Validate the command line options.
180      *
181      * @throws ApexException on command argument validation errors
182      */
183     public void validate() throws ApexException {
184         validateReadableFile("Apex configuration", configurationFilePath);
185
186         if (checkSetModelFilePath()) {
187             validateReadableFile("Apex model", modelFilePath);
188         }
189
190         validateRelativeFileRoot();
191     }
192
193     /**
194      * Print version information for Apex.
195      * 
196      * @return the version string
197      */
198     public String version() {
199         return ResourceUtils.getResourceAsString("version.txt");
200     }
201
202     /**
203      * Print help information for Apex.
204      *
205      * @param mainClassName the main class name
206      * @return the help string
207      */
208     public String help(final String mainClassName) {
209         final StringWriter stringWriter = new StringWriter();
210         final PrintWriter stringPrintWriter = new PrintWriter(stringWriter);
211
212         new HelpFormatter().printHelp(stringPrintWriter, HELP_LINE_LENGTH, mainClassName + " [options...]", "options",
213                         options, 0, 0, "");
214
215         return stringWriter.toString();
216     }
217
218     /**
219      * Gets the model file path.
220      *
221      * @return the model file path
222      */
223     public String getModelFilePath() {
224         return ResourceUtils.getFilePath4Resource(modelFilePath);
225     }
226
227     /**
228      * Sets the model file path.
229      *
230      * @param modelFilePath the model file path
231      */
232     public void setModelFilePath(final String modelFilePath) {
233         this.modelFilePath = modelFilePath;
234     }
235
236     /**
237      * Check set model file path.
238      *
239      * @return true, if check set model file path
240      */
241     public boolean checkSetModelFilePath() {
242         return modelFilePath != null && modelFilePath.length() > 0;
243     }
244
245     /**
246      * Gets the configuration file path.
247      *
248      * @return the configuration file path
249      */
250     public String getConfigurationFilePath() {
251         return configurationFilePath;
252     }
253
254     /**
255      * Gets the root file path for relative file paths in the configuration file.
256      *
257      * @return the root file path
258      */
259     public String getRelativeFileRoot() {
260         return relativeFileRoot;
261     }
262
263     /**
264      * Gets the full expanded configuration file path.
265      *
266      * @return the configuration file path
267      */
268     public String getFullConfigurationFilePath() {
269         return ResourceUtils.getFilePath4Resource(getConfigurationFilePath());
270     }
271
272     /**
273      * Sets the configuration file path.
274      *
275      * @param configurationFilePath the configuration file path
276      */
277     public void setConfigurationFilePath(final String configurationFilePath) {
278         this.configurationFilePath = configurationFilePath;
279
280     }
281
282     /**
283      * Sets the root file path for relative file paths in the configuration file.
284      *
285      * @param relativeFileRoot the configuration file path
286      */
287     public void setRelativeFileRoot(final String relativeFileRoot) {
288         String relativeFileRootValue = relativeFileRoot;
289
290         if (!ParameterValidationUtils.validateStringParameter(relativeFileRoot)) {
291             relativeFileRootValue = System.getProperty(RELATIVE_FILE_ROOT);
292         }
293
294         if (!ParameterValidationUtils.validateStringParameter(relativeFileRootValue)) {
295             relativeFileRootValue = System.getProperty("user.dir");
296         }
297         else if (!(new File(relativeFileRootValue).isAbsolute())) {
298             relativeFileRootValue = System.getProperty("user.dir") + File.separator + relativeFileRootValue;
299         }
300
301         this.relativeFileRoot = relativeFileRootValue;
302         System.setProperty(RELATIVE_FILE_ROOT, relativeFileRootValue);
303     }
304
305     /**
306      * Check set configuration file path.
307      *
308      * @return true, if check set configuration file path
309      */
310     public boolean checkSetConfigurationFilePath() {
311         return configurationFilePath != null && configurationFilePath.length() > 0;
312     }
313
314     /**
315      * Validate readable file.
316      *
317      * @param fileTag the file tag
318      * @param fileName the file name
319      * @throws ApexException the apex exception
320      */
321     private void validateReadableFile(final String fileTag, final String fileName) throws ApexException {
322         if (fileName == null || fileName.length() == 0) {
323             throw new ApexException(fileTag + " file was not specified as an argument");
324         }
325
326         // The file name can refer to a resource on the local file system or on the class path
327         final URL fileUrl = ResourceUtils.getUrl4Resource(fileName);
328         if (fileUrl == null) {
329             throw new ApexException(fileTag + FILE_PREAMBLE + fileName + "\" does not exist");
330         }
331
332         final File theFile = new File(fileUrl.getPath());
333         if (!theFile.exists()) {
334             throw new ApexException(fileTag + FILE_PREAMBLE + fileName + "\" does not exist");
335         }
336         if (!theFile.isFile()) {
337             throw new ApexException(fileTag + FILE_PREAMBLE + fileName + "\" is not a normal file");
338         }
339         if (!theFile.canRead()) {
340             throw new ApexException(fileTag + FILE_PREAMBLE + fileName + "\" is ureadable");
341         }
342     }
343
344     /**
345      * Validate the relative file root.
346      */
347     private void validateRelativeFileRoot() throws ApexException {
348         File relativeFileRootPath = new File(relativeFileRoot);
349         if (!relativeFileRootPath.isDirectory()) {
350             throw new ApexException(
351                             "relative file root \"" + relativeFileRoot + "\" does not exist or is not a directory");
352         }
353
354         if (!relativeFileRootPath.canWrite()) {
355             throw new ApexException(
356                             "relative file root \"" + relativeFileRoot + "\" does not exist or is not a directory");
357         }
358     }
359
360 }