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