View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.rat.documentation.options;
20  
21  import java.util.HashMap;
22  import java.util.Locale;
23  import java.util.Map;
24  import java.util.Optional;
25  import java.util.regex.Matcher;
26  import java.util.regex.Pattern;
27  
28  import org.apache.commons.cli.Option;
29  import org.apache.commons.lang3.StringUtils;
30  import org.apache.rat.OptionCollection;
31  import org.apache.rat.commandline.Arg;
32  
33  import static java.lang.String.format;
34  
35  /**
36   * Abstract class that provides the framework for UI-specific RAT options.
37   * In this context UI option means an option expressed in the specific UI, such as:
38   * @see AntOption
39   * @see MavenOption
40   * @see CLIOption
41   */
42  public abstract class AbstractOption {
43      /** The pattern to match CLI options in text */
44      protected static final Pattern PATTERN = Pattern.compile("-(-[a-z0-9]+)+");
45      /** The actual UI-specific name for the option */
46      protected final Option option;
47      /** The name for the option */
48      protected final String name;
49      /** The argument type for this option */
50      protected final OptionCollection.ArgumentType argumentType;
51  
52      /**
53       * Constructor.
54       *
55       * @param option The CLI option
56       * @param name the UI-specific name for the option.
57       */
58      AbstractOption(final Option option, final String name) {
59          this.option = option;
60          this.name = name;
61          argumentType = option.hasArg() ?
62                  option.getArgName() == null ? OptionCollection.ArgumentType.ARG :
63                  OptionCollection.ArgumentType.valueOf(option.getArgName().toUpperCase(Locale.ROOT)) :
64                  OptionCollection.ArgumentType.NONE;
65      }
66  
67      /**
68       * Gets the option this abstract option is wrapping.
69       * @return the original Option.
70       */
71      public Option getOption() {
72          return option;
73      }
74  
75      /**
76       * Return default value.
77       * @return default value or {@code null} if no argument given.
78       */
79      public String getDefaultValue() {
80          Arg arg = Arg.findArg(option);
81          return arg == null ? null : arg.defaultValue();
82      }
83  
84      /**
85       * Provide means to wrap the given option depending on the UI-specific option implementation.
86       * @param option The CLI option
87       * @return the cleaned up option name.
88       */
89      protected abstract String cleanupName(Option option);
90  
91      /**
92       * Gets an example of how to use this option in the native UI.
93       * @return An example of how to use this option in the native UI.
94       */
95      public abstract String getExample();
96  
97      /**
98       * Gets this option's cleaned up name.
99       * @return This option's cleaned up name.
100      */
101     public String cleanupName() {
102         return cleanupName(option);
103     }
104 
105     /**
106      * Replaces CLI pattern options with implementation specific pattern options.
107      * @param str the string to clean.
108      * @return the string with CLI names replaced with implementation specific names.
109      */
110     public String cleanup(final String str) {
111         String workingStr = str;
112         if (StringUtils.isNotBlank(workingStr)) {
113             Map<String, String> maps = new HashMap<>();
114             Matcher matcher = PATTERN.matcher(workingStr);
115             while (matcher.find()) {
116                 String key = matcher.group();
117                 String optKey = key.substring(2);
118                 Optional<Option> maybeResult = Arg.getOptions().getOptions().stream()
119                         .filter(o -> optKey.equals(o.getOpt()) || optKey.equals(o.getLongOpt())).findFirst();
120                 maybeResult.ifPresent(value -> maps.put(key, cleanupName(value)));
121             }
122             for (Map.Entry<String, String> entry : maps.entrySet()) {
123                 workingStr = workingStr.replaceAll(Pattern.quote(format("%s", entry.getKey())), entry.getValue());
124             }
125         }
126         return workingStr;
127     }
128 
129     /**
130      * Gets the implementation specific name for the CLI option.
131      * @return The implementation specific name for the CLI option.
132      */
133     public final String getName() {
134         return name;
135     }
136 
137     /**
138      * return a string showing long and short options if they are available. Will return
139      * a string.
140      * @return A string showing long and short options if they are available. Never {@code null}.
141      */
142     public abstract String getText();
143 
144     /**
145      * Gets the description in implementation specific format.
146      *
147      * @return the description or an empty string.
148      */
149     public final String getDescription() {
150         return cleanup(option.getDescription());
151     }
152 
153     /**
154      * Gets the simple class name for the data type for this option.
155      * Normally "String".
156      * @return the simple class name for the type.
157      */
158     public final Class<?> getType() {
159         return option.hasArg() ? ((Class<?>) option.getType()) : boolean.class;
160     }
161 
162     /**
163      * Gets the argument name if there is one.
164      * @return the Argument name
165      */
166     public final String getArgName() {
167         return argumentType.getDisplayName();
168     }
169 
170     /**
171      * Gets the argument type if there is one.
172      * @return the Argument name
173      */
174     public final OptionCollection.ArgumentType getArgType() {
175         return argumentType;
176     }
177 
178     /**
179      * Determines if the option is deprecated.
180      * @return {@code true} if the option is deprecated
181      */
182     public final boolean isDeprecated() {
183         return option.isDeprecated();
184     }
185 
186     /**
187      * Determines if the option is required.
188      * @return {@code true} if the option is required.
189      */
190     public final boolean isRequired() {
191         return option.isRequired();
192     }
193 
194     /**
195      * Determine if the enclosed option expects an argument.
196      * @return {@code true} if the enclosed option expects at least one argument.
197      */
198     public final boolean hasArg() {
199         return option.hasArg();
200     }
201 
202     /**
203      * Returns {@code true} if the option has multiple arguments.
204      * @return {@code true} if the option has multiple arguments.
205      */
206     public final boolean hasArgs() {
207         return option.hasArgs();
208     }
209 
210     /**
211      * Returns the number of arguments.
212      * @return The number of arguments.
213      */
214     public final int argCount() {
215         return option.getArgs();
216     }
217 
218     /**
219      * The key value for the option.
220      * @return the key value for the CLI argument map.
221      */
222     public final String keyValue() {
223         return format("\"%s\"", StringUtils.defaultIfEmpty(option.getLongOpt(), option.getOpt()));
224     }
225 
226     /**
227      * Gets the deprecated string if the option is deprecated, or an empty string otherwise.
228      * @return the deprecated string if the option is deprecated, or an empty string otherwise.
229      */
230     public final String getDeprecated() {
231         return  option.isDeprecated() ? cleanup(StringUtils.defaultIfEmpty(option.getDeprecated().toString(), StringUtils.EMPTY)) : StringUtils.EMPTY;
232     }
233 }