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.List;
22  import java.util.Map;
23  import java.util.Optional;
24  import java.util.Set;
25  import java.util.function.Function;
26  
27  import org.apache.commons.cli.Option;
28  import org.apache.rat.ui.UIOption;
29  import org.apache.rat.ui.UIOptionCollection;
30  import org.apache.rat.utils.CasedString;
31  
32  import static java.lang.String.format;
33  
34  /**
35   * A class that wraps the CLI option and provides Ant specific values.
36   */
37  public final class AntOption extends UIOption<AntOption> {
38  
39      /**
40       * Constructor.
41       *
42       * @param builder the AntOptionBuilder
43       */
44      private AntOption(final AntOptionBuilder builder) {
45          super(builder);
46      }
47  
48      /**
49       * Returns {@code true} if the option should be an attribute of the &lt;rat:report&gt; element.
50       *
51       * @return {@code true} if the option should be an attribute of the &lt;rat:report&gt; element.
52       */
53      public boolean isAttribute() {
54          return getAntCollection().isAttribute(this);
55      }
56  
57      @Override
58      public String toString() {
59          return getName();
60      }
61  
62      /**
63       * Returns {@code true} if the option should be a child element of the &lt;rat:report&gt; element.
64       *
65       * @return {@code true} if the option should be a child element of the &lt;rat:report&gt; element.
66       */
67      public boolean isElement() {
68          return !isAttribute();
69      }
70  
71      /**
72       * If this option is converted to another option return that option otherwise
73       * return this option.
74       * @return the converted option.
75       */
76      public AntOption getActualAntOption() {
77          return getAntCollection().getActualAntOption(this);
78      }
79  
80      /**
81       * Gets the set of options that are mapped to this option. This is used to allow one implementation to answer for
82       * multiple options.
83       * @return the set of options that are mapped to this option.
84       */
85      public Set<AntOption> convertedFrom() {
86          return getAntCollection().convertedFrom(this);
87      }
88  
89      @Override
90      public String getText() {
91          return cleanupName(option);
92      }
93  
94      @Override
95      protected String cleanupName(final Option option) {
96          AntOption antOption;
97          if (getOption().equals(option)) {
98              antOption = this;
99          } else {
100             Optional<AntOption> optAntOption = getOptionCollection().getMappedOption(option);
101             if (optAntOption.isPresent()) {
102                 antOption = optAntOption.get();
103             } else {
104                 return "";
105             }
106         }
107         return antOption.cleanupName();
108     }
109 
110     /**
111      * Cleans up the name of this AntOption. Used in documentation.
112      * Returns either {@code <name>} or {@code name attribute}.
113      * @return the cleaned up name.
114      */
115     public String cleanupName() {
116         String fmt = isAttribute() ? "%s attribute" : "<%s>";
117         return format(fmt, name);
118     }
119 
120     /**
121      * Gets the AntOptionCollection this AntOption is associated with.
122      * @return the AntOptionCollection this AntOption is associated with.
123      */
124     AntOptionCollection getAntCollection() {
125         return getOptionCollection();
126     }
127 
128     /**
129      * Gets the Ant build type for this option.
130      * @return the Ant build type for this option.
131      */
132     public AntOptionCollection.BuildType buildType() {
133         return getAntCollection().buildType(this.getArgType());
134     }
135 
136     @Override
137     public String getExample() {
138         return new ExampleGenerator().getExample();
139     }
140 
141     /**
142      * An example code generator for this AntOption.
143      */
144     public class ExampleGenerator {
145 
146         /**
147          * The constructor.
148          */
149         public ExampleGenerator() {
150         }
151 
152         /**
153          * Gets an example Ant XML report call using ant option.
154          * @return the example of this ant option.
155          */
156         String getExample() {
157                 return getExample("data", getAntCollection().getRequiredAttributes(getName()), null);
158         }
159 
160         /**
161          * Gets an example Ant XML report call using ant option with the specified attributes and child elements.
162          * @param data the data value for this option.
163          * @param attributes a map of attribute keys and values.
164          * @param childElements a list of child elements for the example
165          * @return example Ant XML report call using Ant option with the specified attributes and child elements.
166          */
167         public String getExample(final String data, final Map<String, String> attributes, final List<String> childElements) {
168             return "<rat:report" +
169                     getExampleAttributes(data, attributes) +
170                     "> \n" +
171                     getChildElements(data, childElements) +
172                     "</rat:report>\n";
173         }
174 
175         /**
176          * Creates a string comprising the attributes for the Ant XML report call.
177          * @param data the data value for this option.
178          * @param attributes a map of attribute keys and values.
179          * @return a string comprising all the attribute keys and values for the Ant XML report element.
180          */
181         public String getExampleAttributes(final String data, final Map<String, String> attributes) {
182             AntOption actualOption = getActualAntOption();
183             StringBuilder result = new StringBuilder();
184             if (attributes != null) {
185                 attributes.forEach((k, v) -> result.append(format(" %s=\"%s\"", k, v)));
186             }
187             if (actualOption.isAttribute()) {
188                 result.append(format(" %s=\"%s\"", actualOption.getName(), actualOption.hasArg() ? data : "true"));
189             }
190             return result.toString();
191         }
192 
193         /**
194          * Creates a string comprising the child elements for the Ant XML report call.
195          * @param data the data for this option.
196          * @param childElements additional child elements.
197          * @return A string comprising the child elements for the Ant XML report call.
198          */
199         public String getChildElements(final String data, final List<String> childElements) {
200             AntOption baseOption = AntOption.this;
201             AntOption actualOption = getActualAntOption();
202             StringBuilder result = new StringBuilder();
203             if (!actualOption.isAttribute()) {
204                 String inner = getAntCollection().buildType(getArgType()).getXml(actualOption, baseOption, data);
205                 result.append(inner);
206             }
207             if (childElements != null) {
208                 childElements.forEach(x -> result.append(x).append("\n"));
209             }
210             return result.toString();
211         }
212     }
213 
214     /**
215      * The Builder for AntOptions.
216      */
217     public static class AntOptionBuilder extends UIOption.Builder<AntOption, AntOptionBuilder> {
218 
219         public AntOptionBuilder() {
220             super();
221         }
222 
223         /**
224          * returns the function to convert an Option to its Ant based cased name.
225          * @return the function to convert an Option to its Ant based cased name.
226          */
227         protected Function<Option, CasedString> getNameFactory() {
228             return this::createName;
229         }
230 
231         @Override
232         public AntOptionBuilder optionCollection(final UIOptionCollection<AntOption> optionCollection) {
233             if (optionCollection instanceof AntOptionCollection) {
234                 return super.optionCollection(optionCollection);
235             }
236             throw new IllegalArgumentException("Option collection must be instance of AntOptionCollection");
237         }
238 
239         @Override
240         protected AntOption doBuild() {
241             return new AntOption(this);
242         }
243 
244         /**
245          * Creates the name for the option based on rules for conversion of Option names.
246          * Ant names are in PASCAL format.
247          * @param option the standard option.
248          * @return a new CasedString comprising the name of the AntOption.
249          * @see CasedString.StringCase#PASCAL
250          */
251         CasedString createName(final Option option) {
252             List<String> pluralEndings = List.of("approved", "denied");
253             String name = optionCollection().rename(option);
254             CasedString casedName = new CasedString(CasedString.StringCase.KEBAB, name);
255             String[] segments = casedName.getSegments();
256             String lastSegment = segments[segments.length - 1];
257             if (option.hasArgs() && !lastSegment.endsWith("s") && !pluralEndings.contains(lastSegment)) {
258                 segments[segments.length - 1] += "s";
259                 casedName = new CasedString(CasedString.StringCase.KEBAB, segments);
260             }
261             return casedName.as(CasedString.StringCase.PASCAL);
262         }
263     }
264 }