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   *   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 }