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 <rat:report> element.
50 *
51 * @return {@code true} if the option should be an attribute of the <rat:report> 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 <rat:report> element.
64 *
65 * @return {@code true} if the option should be a child element of the <rat:report> 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 }