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 * https://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.ui;
20
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Objects;
27 import java.util.Optional;
28 import java.util.TreeMap;
29 import java.util.function.BiFunction;
30 import java.util.stream.Stream;
31
32 import org.apache.commons.cli.Option;
33 import org.apache.commons.cli.Options;
34 import org.apache.rat.Defaults;
35 import org.apache.rat.commandline.Arg;
36 import org.apache.rat.utils.Log;
37
38 /**
39 * A collection of options supported by the UI. This includes RAT options and UI specific options.
40 * @param <T> the AbstractOption implementation.
41 */
42 public class UIOptionCollection<T extends UIOption<T>> {
43 /** map of ARG to the associated UpdatableOptionGroup */
44 private final Map<Arg, UpdatableOptionGroup> argMap;
45 /** set of RAT OptionGroups with unsupported options for this UI removed */
46 private final UpdatableOptionGroupCollection supportedRatOptions;
47 /** set of UI specific options */
48 private final Map<Option, T> uiOptions;
49 /**
50 * Map of option to overridden default value. Generally applies to supported RAT options but may be
51 * UI-specific options as well.
52 */
53 private final Map <Option, String> defaultValues;
54
55 /**
56 * The function to generate a concrete BaseOption instance.
57 */
58 private final BiFunction<UIOptionCollection<T>, Option, T> mapper;
59
60 /**
61 * Construct the UIOptionCollection from the builder.
62 * @param builder the builder to build from.
63 */
64 protected UIOptionCollection(final Builder<T, ?> builder) {
65 Objects.requireNonNull(builder.mapper, "Builder.mapper");
66 argMap = new TreeMap<>();
67 mapper = builder.mapper;
68 supportedRatOptions = new UpdatableOptionGroupCollection();
69
70 for (Arg arg : Arg.values()) {
71 argMap.put(arg, supportedRatOptions.add(arg.group()));
72 }
73
74 for (Option opt : builder.unsupportedRatOptions) {
75 supportedRatOptions.findGroups(opt).forEach(group -> group.disableOption(opt));
76 }
77 uiOptions = new HashMap<>();
78 supportedRatOptions.options().getOptions()
79 .forEach(option -> uiOptions.put(option, mapper.apply(this, option)));
80 builder.uiOptions.stream().filter(option -> !uiOptions.containsKey(option))
81 .forEach(option -> uiOptions.put(option, mapper.apply(this, option)));
82 defaultValues = new HashMap<>(builder.defaultValues);
83 }
84
85 /**
86 * Checks if an Arg is selected.
87 * @param arg the Arg to check.
88 * @return {@code true} if the arg is selected.
89 */
90 public final boolean isSelected(final Arg arg) {
91 UpdatableOptionGroup group = argMap.get(arg);
92 return group != null && group.getSelected() != null;
93 }
94
95 /**
96 * Gets the selected Option for the arg.
97 * @param arg the arg to check.
98 * @return an Optional containing the selected option, or an empty Optional if none was selected.
99 */
100 public final Optional<Option> getSelected(final Arg arg) {
101 UpdatableOptionGroup group = argMap.get(arg);
102 String s = group == null ? null : group.getSelected();
103 if (s != null) {
104 for (Option result : group.getOptions()) {
105 if (result.getKey().equals(s)) {
106 return Optional.of(result);
107 }
108 }
109 }
110 return Optional.empty();
111 }
112
113 /**
114 * Gets the collection of unsupported Options.
115 * @return the Options comprised for the unsupported options.
116 */
117 public final Options getUnsupportedOptions() {
118 return supportedRatOptions.unsupportedOptions();
119 }
120
121 /**
122 * Gets the UiOption instance for the Option.
123 * @param option the option to find the instance of.
124 * @return a UIOption instance that wraps the option.
125 */
126 public final Optional<T> getMappedOption(final Option option) {
127 return Optional.ofNullable(uiOptions.get(option));
128 }
129
130 /**
131 * Gets an Options that contains the RAT Arg defined Option instances that are understood by this collection.
132 * OptionGroups are registered in the resulting Options object.
133 * @return an Options that contains the RAT Arg defined Option instances that are understood by this collection.
134 */
135 public final Options getOptions() {
136 return supportedRatOptions.options().addOptions(additionalOptions());
137 }
138
139 /**
140 * Gets the Stream of AbstractOption implementations understood by this collection.
141 * @return the Stream of AbstractOption implementations understood by this collection.
142 */
143 public final Stream<T> getMappedOptions() {
144 return uiOptions.values().stream();
145 }
146
147 /**
148 * Gets a map client option name to specified AbstractOption implementation.
149 * @return a map client option name to specified AbstractOption implementation
150 */
151 public final Map<String, T> getOptionMap() {
152 Map<String, T> result = new TreeMap<>();
153 getMappedOptions().forEach(mappedOption -> result.put(ArgumentTracker.extractKey(mappedOption.getOption()), mappedOption));
154 return result;
155 }
156
157 /**
158 * Gets the additional options understood by this collection.
159 * @return the additional options understood by this collection.
160 */
161 public final Options additionalOptions() {
162 Options options = new Options();
163 uiOptions.keySet().stream()
164 .filter(option -> !supportedRatOptions.contains(option))
165 .forEach(options::addOption);
166 return options;
167 }
168
169 /**
170 * Gets the default value for the option.
171 * @param option the option to lookup.
172 * @return the default value or {@code null} if not set.
173 */
174 public final String defaultValue(final Option option) {
175 return defaultValues.get(option);
176 }
177
178 /**
179 * Builder for a BaseOptionCollection.
180 * @param <T> the concreate type of the BaseOption.
181 * @param <S> the concrete type being built.
182 */
183 protected static class Builder<T extends UIOption<T>, S extends Builder<T, S>> {
184 /** set of additional UI specific options */
185 private final List<Option> uiOptions;
186 /**
187 * Map of option to overridden default value. Generally applies to supported RAT options but may be
188 * UI-specific options as well.
189 */
190 private final Map <Option, String> defaultValues;
191 /** The list of unsupported RAT options. */
192 protected final List<Option> unsupportedRatOptions;
193 /** The function to convert an option into a UIOption. */
194 private final BiFunction<UIOptionCollection<T>, Option, T> mapper;
195
196 /**
197 * Constructor for the builder.
198 */
199 protected Builder(final BiFunction<UIOptionCollection<T>, Option, T> mapper) {
200 this.mapper = mapper;
201 uiOptions = new ArrayList<>();
202 defaultValues = new HashMap<>();
203 unsupportedRatOptions = new ArrayList<>();
204 defaultValue(Arg.LOG_LEVEL, Log.Level.WARN.name());
205 defaultValue(Arg.OUTPUT_ARCHIVE, Defaults.ARCHIVE_PROCESSING.name());
206 defaultValue(Arg.OUTPUT_STANDARD, Defaults.STANDARD_PROCESSING.name());
207 defaultValue(Arg.OUTPUT_LICENSES, Defaults.LIST_LICENSES.name());
208 defaultValue(Arg.OUTPUT_FAMILIES, Defaults.LIST_FAMILIES.name());
209 }
210
211 /**
212 * Build the UIOptionCollection.
213 * @return the UIOptionCollection.
214 */
215 public UIOptionCollection<T> build() {
216 return new UIOptionCollection<>(this);
217 }
218
219 /**
220 * Returns this cast to {@code <S>} class.
221 * @return this as {@code <S>} class.
222 */
223 protected final S self() {
224 return (S) this;
225 }
226
227 /**
228 * Add a UI option to the collection.
229 * @param uiOption the UI Option to add.
230 * @return this
231 */
232 public S uiOption(final Option uiOption) {
233 uiOptions.add(uiOption);
234 return self();
235 }
236
237 /**
238 * Add a UI options to the collection.
239 * @param uiOption the UIOptions ({@code <T>} objects) to add.
240 * @return this
241 */
242 public S uiOptions(final Option... uiOption) {
243 uiOptions.addAll(Arrays.asList(uiOption));
244 return self();
245 }
246
247 /**
248 * Register an option as unsupported.
249 * @param option the option that is not be supported. This should be an option in the
250 * {@link Arg} collection.
251 * @return this
252 */
253 public S unsupported(final Option option) {
254 unsupportedRatOptions.add(option);
255 return self();
256 }
257
258 /**
259 * Register multiple options as unsupported.
260 * Will ignore all the options associated with the specified Arg.
261 * @param arg The Arg to ignore.
262 * @return this
263 */
264 public S unsupported(final Arg arg) {
265 unsupportedRatOptions.addAll(arg.group().getOptions());
266 return self();
267 }
268
269 /**
270 * Specify the default values for an option.
271 * @param option the option to specify the default value for.
272 * @param value the value for the option.
273 * @return this
274 */
275 public S defaultValue(final Option option, final String value) {
276 defaultValues.put(option, value);
277 return self();
278 }
279
280 /**
281 * Specify the default values for an Arg.
282 * @param arg the Arg to specify the default value for.
283 * @param value the value for the option.
284 * @return this
285 */
286 public S defaultValue(final Arg arg, final String value) {
287 return defaultValue(arg.option(), value);
288 }
289 }
290 }