Merge "Improve RpcProviderRegistry loading"
[controller.git] / opendaylight / commons / filter-valve / src / main / java / org / opendaylight / controller / filtervalve / cors / model / UrlMatcher.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.filtervalve.cors.model;
10
11 import static com.google.common.base.Preconditions.checkNotNull;
12 import static com.google.common.collect.Maps.immutableEntry;
13
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.LinkedHashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.TreeMap;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 /**
25  * Match incoming URL with user defined patterns according to servlet specification.
26  * In the Web application deployment descriptor, the following syntax is used to define mappings:
27  * <ul>
28  * <li>A string beginning with a ‘/’ character and ending with a ‘/*’ suffix is used for path mapping.</li>
29  * <li>A string beginning with a ‘*.’ prefix is used as an extension mapping.</li>
30  * <li>All other strings are used for exact matches only.</li>
31  * </ul>
32  */
33 public class UrlMatcher<FILTER> {
34     private static final Logger logger = LoggerFactory.getLogger(UrlMatcher.class);
35     // order index for each FILTER is kept as Entry.value
36     private final Map<String, Entry<FILTER, Integer>> prefixMap = new HashMap<>(); // contains patterns ending with '/*', '*' is stripped from each key
37     private final Map<String, Entry<FILTER, Integer>> suffixMap = new HashMap<>(); // contains patterns starting with '*.' prefix, '*' is stripped from each key
38     private final Map<String, Entry<FILTER, Integer>> exactMatchMap = new HashMap<>(); // contains exact matches only
39
40     /**
41      * @param patternMap order preserving map containing path info pattern as key
42      */
43     public UrlMatcher(LinkedHashMap<String, FILTER> patternMap) {
44         int idx = 0;
45         for (Entry<String, FILTER> entry : patternMap.entrySet()) {
46             idx++;
47             String pattern = checkNotNull(entry.getKey());
48             FILTER value = entry.getValue();
49             Entry<FILTER, Integer> valueWithIdx = immutableEntry(value, idx);
50             if (pattern.startsWith("/") && pattern.endsWith("/*")) {
51                 pattern = pattern.substring(0, pattern.length() - 1);
52                 prefixMap.put(pattern, valueWithIdx);
53             } else if (pattern.startsWith("*.")) {
54                 pattern = pattern.substring(1);
55                 suffixMap.put(pattern, valueWithIdx);
56             } else {
57                 exactMatchMap.put(pattern, valueWithIdx);
58             }
59         }
60     }
61
62     /**
63      * Find filters matching path
64      *
65      * @param path relative and decoded path to resource
66      * @return list of matching filters
67      */
68     public List<FILTER> findMatchingFilters(String path) {
69         checkNotNull(path);
70         TreeMap<Integer, FILTER> sortedMap = new TreeMap<>();
71         // add matching prefixes
72         for (Entry<String, Entry<FILTER, Integer>> prefixEntry : prefixMap.entrySet()) {
73             if (path.startsWith(prefixEntry.getKey())) {
74                 put(sortedMap, prefixEntry.getValue());
75             }
76         }
77         // add matching suffixes
78         for (Entry<String, Entry<FILTER, Integer>> suffixEntry : suffixMap.entrySet()) {
79             if (path.endsWith(suffixEntry.getKey())) {
80                 put(sortedMap, suffixEntry.getValue());
81             }
82         }
83         // add exact match
84         Entry<FILTER, Integer> exactMatch = exactMatchMap.get(path);
85         if (exactMatch != null) {
86             put(sortedMap, exactMatch);
87         }
88         ArrayList<FILTER> filters = new ArrayList<>(sortedMap.values());
89         logger.trace("Matching filters for path {} are {}", path, filters);
90         return filters;
91     }
92
93     private void put(TreeMap<Integer, FILTER> sortedMap, Entry<FILTER, Integer> entry) {
94         sortedMap.put(entry.getValue(), entry.getKey());
95     }
96 }