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.configuration.builders;
20  
21  import java.util.Map;
22  
23  import org.apache.rat.ConfigurationException;
24  import org.apache.rat.analysis.IHeaderMatcher;
25  import org.apache.rat.analysis.IHeaders;
26  import org.apache.rat.config.parameters.ComponentType;
27  import org.apache.rat.config.parameters.ConfigComponent;
28  import org.apache.rat.config.parameters.MatcherBuilder;
29  
30  /**
31   * A reference matching Matcher builder.
32   * <p>
33   * This class stores a matcher id as a reference to the matcher. It also has a
34   * map of matcher ids to the matcher instances. When {@code build()} is called the matcher
35   * reference is looked up in the map. If it is found then its value is returned
36   * from the {@code build()} call. If the reference is not located then a
37   * IHeaderMatcherProxy is returned. the IHeaderMatcherProxy is resolved in a
38   * later configuration construction phase.
39   */
40  @MatcherBuilder(MatcherRefBuilder.IHeaderMatcherProxy.class)
41  public class MatcherRefBuilder extends AbstractBuilder {
42      /** The matcher id that this builder references */
43      private String referenceId;
44      /** The map of matcher id to matcher maintained by the system. Used for lookup. */
45      private Map<String, IHeaderMatcher> matchers;
46  
47      /**
48       * Constructs the MatcherReferenceBuilder using the provided reference id.
49       *
50       * @param refId the reverence to the matcher id.
51       * @return this builder for chaining.
52       */
53      public MatcherRefBuilder setRefId(final String refId) {
54          // this method is called by reflection
55          this.referenceId = refId;
56          return this;
57      }
58  
59      /**
60       * Set the Map of matcher ids to matcher instances.
61       *
62       * @param matchers the Map of ids to instances.
63       * @return this builder for chaining.
64       */
65      public MatcherRefBuilder setMatcherMap(final Map<String, IHeaderMatcher> matchers) {
66          // this method is called by reflection
67          this.matchers = matchers;
68          return this;
69      }
70  
71      @Override
72      public IHeaderMatcher build() {
73          if (matchers == null) {
74              throw new ConfigurationException("'matchers' not set");
75          }
76          IHeaderMatcher result = matchers.get(referenceId);
77          return result != null ? result : new IHeaderMatcherProxy(referenceId, matchers);
78      }
79  
80      @Override
81      public String toString() {
82          return "MatcherRefBuilder: " + referenceId;
83      }
84  
85      /**
86       * A class that is a proxy to the actual matcher. It retrieves the actual
87       * matcher from the map of matcher ids to matcher instances on the first use of
88       * the matcher. This allows earlier read matchers to reference later constructed
89       * matchers as long as all the matchers are constructed before the earlier one
90       * is used.
91       */
92      @ConfigComponent(type = ComponentType.MATCHER, name = "matcherRef", desc = "A pointer to another Matcher")
93      public static class IHeaderMatcherProxy implements IHeaderMatcher {
94          /**
95           * The reference id (aka proxyId) for the reference.
96           */
97          @ConfigComponent(type = ComponentType.PARAMETER, name = "refId", desc = "Reference to an existing matcher", required = true)
98          private final String proxyId;
99          /** The header matcher that this proxy points to */
100         private IHeaderMatcher wrapped;
101         /** The map of reference IDs to matchers that is maintained in the build environment. Used for lookup */
102         @ConfigComponent(type = ComponentType.BUILD_PARAMETER, name = "matcherMap", desc = "Map of matcher names to matcher instances")
103         private Map<String, IHeaderMatcher> matchers;
104 
105         /**
106          * Constructor. The matchers map should be a reference to an object that will be
107          * updated by later processing of matcher definitions.
108          *
109          * @param proxyId the id of the matcher to find.
110          * @param matchers a mapping of matchers that have been found.
111          */
112         public IHeaderMatcherProxy(final String proxyId, final Map<String, IHeaderMatcher> matchers) {
113             this.proxyId = proxyId;
114             this.matchers = matchers;
115         }
116 
117         private void checkProxy() {
118             if (wrapped == null) {
119                 wrapped = matchers.get(proxyId);
120                 if (wrapped == null) {
121                     throw new IllegalStateException(String.format("%s is not a valid matcher id", proxyId));
122                 }
123                 matchers = null;
124             }
125         }
126 
127         @Override
128         public String getId() {
129             checkProxy();
130             return wrapped.getId();
131         }
132 
133         @Override
134         public void reset() {
135             checkProxy();
136             wrapped.reset();
137         }
138 
139         @Override
140         public boolean matches(final IHeaders header) {
141             checkProxy();
142             return wrapped.matches(header);
143         }
144 
145         /**
146          * Gets the matcher ID that this proxy references.
147          * @return The matcher ID that this proxy references.
148          */
149         public String getRefId() {
150             // called by introspection
151             return proxyId;
152         }
153     }
154 }