blob: e17e2e6748ddaa171772955ad721f2ceb2cdb698 [file] [log] [blame]
/*
* 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
*
* https://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.ivy.core.module.id;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.ivy.plugins.matcher.MapMatcher;
import org.apache.ivy.util.Checks;
import org.apache.ivy.util.Message;
import org.apache.ivy.util.filter.Filter;
import org.apache.ivy.util.filter.NoFilter;
/**
* A list of module specific rules.
* <p>
* This class defines a list of module specific rules. For each module only one rule apply,
* sometimes none.
* </p>
* <p>
* To know which rule to apply, they are configured using matchers. So you can define a rule
* applying to all module from one particular organization, or to all modules with a revisions
* matching a pattern, and so on.
* </p>
* <p>
* Rules condition are evaluated in order, so the first matching rule is returned.
* </p>
* <p>
* Rules themselves can be represented by any object, depending on the purpose of the rule (define
* which resolver to use, which TTL in cache, ...)
* </p>
*
* @param <T> a type parameter
*/
public class ModuleRules<T> {
private Map<MapMatcher, T> rules = new LinkedHashMap<>();
private MatcherLookup matcherLookup = new MatcherLookup();
/**
* Constructs an empty ModuleRules.
*/
public ModuleRules() {
}
private ModuleRules(Map<MapMatcher, T> rules) {
this.rules = new LinkedHashMap<>(rules);
for (MapMatcher matcher : rules.keySet()) {
matcherLookup.add(matcher);
}
}
/**
* Defines a new rule for the given condition.
*
* @param condition
* the condition for which the rule should be applied. Must not be <code>null</code>.
* @param rule
* the rule to apply. Must not be <code>null</code>.
*/
public void defineRule(MapMatcher condition, T rule) {
Checks.checkNotNull(condition, "condition");
Checks.checkNotNull(rule, "rule");
rules.put(condition, rule);
matcherLookup.add(condition);
}
/**
* Returns the rule object matching the given {@link ModuleId}, or <code>null</code> if no rule
* applies.
*
* @param mid
* the {@link ModuleId} to search the rule for. Must not be <code>null</code>.
* @return the rule object matching the given {@link ModuleId}, or <code>null</code> if no rule
* applies.
* @see #getRule(ModuleId, Filter)
*/
public T getRule(ModuleId mid) {
return getRule(mid, NoFilter.<T> instance());
}
/**
* Returns the rules objects matching the given {@link ModuleId}, or an empty array if no rule
* applies.
*
* @param mid
* the {@link ModuleId} to search the rule for. Must not be <code>null</code>.
* @return an array of rule objects matching the given {@link ModuleId}.
*/
public List<T> getRules(ModuleId mid) {
return getRules(mid.getAttributes(), NoFilter.<T> instance());
}
/**
* Returns the rule object matching the given {@link ModuleRevisionId}, or <code>null</code> if
* no rule applies.
*
* @param mrid
* the {@link ModuleRevisionId} to search the rule for. Must not be <code>null</code>
* .
* @return the rule object matching the given {@link ModuleRevisionId}, or <code>null</code> if
* no rule applies.
* @see #getRule(ModuleRevisionId, Filter)
*/
public T getRule(ModuleRevisionId mrid) {
return getRule(mrid, NoFilter.<T> instance());
}
/**
* Returns the rule object matching the given {@link ModuleId} and accepted by the given
* {@link Filter}, or <code>null</code> if no rule applies.
*
* @param mid
* the {@link ModuleRevisionId} to search the rule for. Must not be <code>null</code>
* .
* @param filter
* the filter to use to filter the rule to return. The {@link Filter#accept(Object)}
* method will be called only with rule objects matching the given {@link ModuleId},
* and the first rule object accepted by the filter will be returned. Must not be
* <code>null</code>.
* @return the rule object matching the given {@link ModuleId}, or <code>null</code> if no rule
* applies.
* @see #getRule(ModuleRevisionId, Filter)
*/
public T getRule(ModuleId mid, Filter<T> filter) {
Checks.checkNotNull(mid, "mid");
return getRule(mid.getAttributes(), filter);
}
/**
* Returns the rule object matching the given {@link ModuleRevisionId} and accepted by the given
* {@link Filter}, or <code>null</code> if no rule applies.
*
* @param mrid
* the {@link ModuleRevisionId} to search the rule for. Must not be <code>null</code>
* .
* @param filter
* the filter to use to filter the rule to return. The {@link Filter#accept(Object)}
* method will be called only with rule objects matching the given
* {@link ModuleRevisionId}, and the first rule object accepted by the filter will be
* returned. Must not be <code>null</code>.
* @return the rule object matching the given {@link ModuleRevisionId}, or <code>null</code> if
* no rule applies.
* @see #getRule(ModuleRevisionId)
*/
public T getRule(ModuleRevisionId mrid, Filter<T> filter) {
Checks.checkNotNull(mrid, "mrid");
Checks.checkNotNull(filter, "filter");
Map<String, String> moduleAttributes = mrid.getAttributes();
return getRule(moduleAttributes, filter);
}
private T getRule(Map<String, String> moduleAttributes, Filter<T> filter) {
for (MapMatcher midm : matcherLookup.get(moduleAttributes)) {
T rule = rules.get(midm);
if (filter.accept(rule)) {
return rule;
}
}
return null;
}
/**
* Returns the rules object matching the given {@link ModuleRevisionId} and accepted by the
* given {@link Filter}, or an empty array if no rule applies.
*
* @param mrid
* the {@link ModuleRevisionId} to search the rule for. Must not be <code>null</code>
* .
* @param filter
* the filter to use to filter the rule to return. The {@link Filter#accept(Object)}
* method will be called only with rule objects matching the given
* {@link ModuleRevisionId}. Must not be <code>null</code>.
* @return an array of rule objects matching the given {@link ModuleRevisionId}.
*/
public List<T> getRules(ModuleRevisionId mrid, Filter<T> filter) {
Checks.checkNotNull(mrid, "mrid");
Checks.checkNotNull(filter, "filter");
Map<String, String> moduleAttributes = mrid.getAttributes();
return getRules(moduleAttributes, filter);
}
private List<T> getRules(Map<String, String> moduleAttributes, Filter<T> filter) {
List<T> matchingRules = new ArrayList<>();
for (MapMatcher midm : matcherLookup.get(moduleAttributes)) {
T rule = rules.get(midm);
if (filter.accept(rule)) {
matchingRules.add(rule);
}
}
return matchingRules;
}
/**
* Dump the list of rules to {@link Message#debug(String)}
*
* @param prefix
* the prefix to use for each line dumped
*/
public void dump(String prefix) {
if (rules.isEmpty()) {
Message.debug(prefix + "NONE");
return;
}
for (Map.Entry<MapMatcher, T> entry : rules.entrySet()) {
MapMatcher midm = entry.getKey();
T rule = entry.getValue();
Message.debug(prefix + midm + " -> " + rule);
}
}
/**
* Returns an unmodifiable view of all the rules defined on this ModuleRules.
* <p>
* The rules are returned in a Map where they keys are the MapMatchers matching the rules
* object, and the values are the rules object themselves.
* </p>
*
* @return an unmodifiable view of all the rules defined on this ModuleRules.
*/
public Map<MapMatcher, T> getAllRules() {
return Collections.unmodifiableMap(rules);
}
public ModuleRules<T> clone() {
return new ModuleRules<>(rules);
}
}