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