MatcherRefBuilder.java
/*
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you under the Apache License, Version 2.0 (the *
* "License"); you may not use this file except in compliance *
* with the License. You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, *
* software distributed under the License is distributed on an *
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
* KIND, either express or implied. See the License for the *
* specific language governing permissions and limitations *
* under the License. *
*/
package org.apache.rat.configuration.builders;
import java.util.Map;
import org.apache.rat.ConfigurationException;
import org.apache.rat.analysis.IHeaderMatcher;
import org.apache.rat.analysis.IHeaders;
import org.apache.rat.config.parameters.ComponentType;
import org.apache.rat.config.parameters.ConfigComponent;
import org.apache.rat.config.parameters.MatcherBuilder;
/**
* A reference matching Matcher builder.
* <p>
* This class stores a matcher id as a reference to the matcher. It also has a
* map of matcher ids to the matcher instances. When {@code build()} is called the matcher
* reference is looked up in the map. If it is found then its value is returned
* from the {@code build()} call. If the reference is not located then a
* IHeaderMatcherProxy is returned. the IHeaderMatcherProxy is resolved in a
* later configuration construction phase.
*/
@MatcherBuilder(MatcherRefBuilder.IHeaderMatcherProxy.class)
public class MatcherRefBuilder extends AbstractBuilder {
/** The matcher id that this builder references */
private String referenceId;
/** The map of matcher id to matcher maintained by the system. Used for lookup. */
private Map<String, IHeaderMatcher> matchers;
/**
* Constructs the MatcherReferenceBuilder using the provided reference id.
*
* @param refId the reverence to the matcher id.
* @return this builder for chaining.
*/
public MatcherRefBuilder setRefId(final String refId) {
// this method is called by reflection
this.referenceId = refId;
return this;
}
/**
* Set the Map of matcher ids to matcher instances.
*
* @param matchers the Map of ids to instances.
* @return this builder for chaining.
*/
public MatcherRefBuilder setMatcherMap(final Map<String, IHeaderMatcher> matchers) {
// this method is called by reflection
this.matchers = matchers;
return this;
}
@Override
public IHeaderMatcher build() {
if (matchers == null) {
throw new ConfigurationException("'matchers' not set");
}
IHeaderMatcher result = matchers.get(referenceId);
return result != null ? result : new IHeaderMatcherProxy(referenceId, matchers);
}
@Override
public String toString() {
return "MatcherRefBuilder: " + referenceId;
}
/**
* A class that is a proxy to the actual matcher. It retrieves the actual
* matcher from the map of matcher ids to matcher instances on the first use of
* the matcher. This allows earlier read matchers to reference later constructed
* matchers as long as all the matchers are constructed before the earlier one
* is used.
*/
@ConfigComponent(type = ComponentType.MATCHER, name = "matcherRef", desc = "A pointer to another Matcher")
public static class IHeaderMatcherProxy implements IHeaderMatcher {
/**
* The reference id (aka proxyId) for the reference.
*/
@ConfigComponent(type = ComponentType.PARAMETER, name = "refId", desc = "Reference to an existing matcher", required = true)
private final String proxyId;
/** The header matcher that this proxy points to */
private IHeaderMatcher wrapped;
/** The map of reference IDs to matchers that is maintained in the build environment. Used for lookup */
@ConfigComponent(type = ComponentType.BUILD_PARAMETER, name = "matcherMap", desc = "Map of matcher names to matcher instances")
private Map<String, IHeaderMatcher> matchers;
/**
* Constructor. The matchers map should be a reference to an object that will be
* updated by later processing of matcher definitions.
*
* @param proxyId the id of the matcher to find.
* @param matchers a mapping of matchers that have been found.
*/
public IHeaderMatcherProxy(final String proxyId, final Map<String, IHeaderMatcher> matchers) {
this.proxyId = proxyId;
this.matchers = matchers;
}
private void checkProxy() {
if (wrapped == null) {
wrapped = matchers.get(proxyId);
if (wrapped == null) {
throw new IllegalStateException(String.format("%s is not a valid matcher id", proxyId));
}
matchers = null;
}
}
@Override
public String getId() {
checkProxy();
return wrapped.getId();
}
@Override
public void reset() {
checkProxy();
wrapped.reset();
}
@Override
public boolean matches(final IHeaders header) {
checkProxy();
return wrapped.matches(header);
}
/**
* Gets the matcher ID that this proxy references.
* @return The matcher ID that this proxy references.
*/
public String getRefId() {
// called by introspection
return proxyId;
}
}
}