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 }