/* * 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.ivy.core.module.id; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ivy.core.IvyPatternHelper; import org.apache.ivy.plugins.matcher.ExactPatternMatcher; import org.apache.ivy.plugins.matcher.MapMatcher; import org.apache.ivy.plugins.matcher.PatternMatcher; /** * This class targets to speed up lookup for exact pattern matcher by keys, which are created with * (organization, module) information. When exact pattern matcher is added, the key is created from * matcher's attributes. When matcher is looked up against specific module, the key is recreated * from module's attributes. * <p> * </p> * The lookup doesn't target to speed up lookup for non exact pattern matcher. All non exact * matchers are placed in non-keyed collection. * <p> * </p> * At lookup for matchers against specific module, all non exact pattern matchers are iterated to * match with module attributes, and exact pattern matchers binding to the same key will also * iterated to match with module attributes. * <p> * </p> * If there are much more exact pattern matchers than non exact pattern matchers, the matcher lookup * speed can benefit from this class significantly. A quick example could be user declares lots of * dependencyOverrides which are typically exact pattern matchers. * <p> * </p> * If there are balanced exact and non exact pattern matchers, the matcher lookup speed doesn't hurt * by this class. * <p> * </p> */ public class MatcherLookup { // private static final String FORMAT = "{org:%s, module:%s}"; private static final String DEFAULT = "{org:" + "default" + ", module:" + "default" + "}"; private Map<String, List<MapMatcher>> lookup = new HashMap<String, List<MapMatcher>>(); private List<MapMatcher> non_exact_matchers = new ArrayList<MapMatcher>(); /** * Add matcher. * * If matcher is exact pattern matcher, it will be associated with a key and placed in keyed * collection. * * If matcher is not exact pattern matcher, it will be placed into non-keyed collection * * @param matcher */ public void add(MapMatcher matcher) { if (!(matcher.getPatternMatcher() instanceof ExactPatternMatcher)) { non_exact_matchers.add(matcher); return; } String key = key(matcher.getAttributes()); List<MapMatcher> exact_matchers = lookup.get(key); if (exact_matchers == null) { exact_matchers = new ArrayList<MapMatcher>(); lookup.put(key, exact_matchers); } exact_matchers.add(matcher); } /** * Get a list of matchers which can apply to module with specified attributes * * @param attrs * A map of attributes that matcher should match. * * @return list A list of candidate matchers that matches specified attributes */ public List<MapMatcher> get(Map<String, String> attrs) { List<MapMatcher> matchers = new ArrayList<MapMatcher>(); // Step 1: find matchers from non_exact_matchers list if (!non_exact_matchers.isEmpty()) { for (MapMatcher matcher : non_exact_matchers) { if (matcher.matches(attrs)) { matchers.add(matcher); } } } // Step 2: find matchers from exact_matchers list of key String key = key(attrs); List<MapMatcher> exact_matchers = lookup.get(key); if (exact_matchers != null) { for (MapMatcher matcher : exact_matchers) { if (matcher.matches(attrs)) { matchers.add(matcher); } } } // Step 3: (iff key != DEFAULT) find matchers from exact_matchers of DEFAULT if (key != DEFAULT) { List<MapMatcher> default_exact_matchers = lookup.get(DEFAULT); if (default_exact_matchers != null) { for (MapMatcher matcher : default_exact_matchers) { if (matcher.matches(attrs)) { matchers.add(matcher); } } } } return matchers; } /** * Create a key from specified attributes * * @param attrs * A map of attributes * @return key object */ private String key(Map<String, String> attrs) { String org = attrs.get(IvyPatternHelper.ORGANISATION_KEY); String module = attrs.get(IvyPatternHelper.MODULE_KEY); if (org == null || PatternMatcher.ANY_EXPRESSION.equals(org) || module == null || PatternMatcher.ANY_EXPRESSION.equals(module)) { return DEFAULT; } return "{org:" + org + ", module:" + module + "}"; } }