KNOX-1157 - Scoped rewrite rules are treated as global rules in some cases (Wei Han...
[knox.git] / gateway-provider-rewrite / src / main / java / org / apache / knox / gateway / filter / rewrite / ext / ScopedMatcher.java
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 * <p>
10 * http://www.apache.org/licenses/LICENSE-2.0
11 * <p>
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package org.apache.knox.gateway.filter.rewrite.ext;
19
20 import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteRuleProcessorHolder;
21 import org.apache.knox.gateway.util.urltemplate.Matcher;
22 import org.apache.knox.gateway.util.urltemplate.Template;
23
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.HashMap;
27
28 /**
29 * A simple extension to the matcher that takes into account scopes for rules along with the templates themselves.
30 * This matcher maintains a list of matchers and delegates to an appropriate matcher based on scope information for the
31 * associated rules.
32 */
33 public class ScopedMatcher extends Matcher<UrlRewriteRuleProcessorHolder> {
34
35 public static final String GLOBAL_SCOPE = "GLOBAL";
36
37 private HashMap<String, Matcher<UrlRewriteRuleProcessorHolder>> matchers;
38
39 public ScopedMatcher() {
40 super();
41 matchers = new HashMap<>();
42 }
43
44 @Override
45 public UrlRewriteRuleProcessorHolder get(Template template) {
46 return super.get(template);
47 }
48
49 @Override
50 public void add(Template template, UrlRewriteRuleProcessorHolder value) {
51 Matcher<UrlRewriteRuleProcessorHolder> matcher = getMatcher(template, value);
52 matcher.add( template, value );
53 }
54
55 @Override
56 public Match match(Template input) {
57 return match(input, null);
58 }
59
60 public Match match(Template input, String scope) {
61 List<Match> matches = new ArrayList<>();
62 for (Matcher<UrlRewriteRuleProcessorHolder> matcher : matchers.values()) {
63 Match match = matcher.match(input);
64 if (match != null) {
65 matches.add(match);
66 }
67 }
68 if (matches.size() == 0) {
69 return null;
70 }
71 if (matches.size() == 1) {
72 return getMatch(matches, scope);
73 }
74 return findBestMatch(matches, scope);
75 }
76
77 private Match findBestMatch(List<Match> matches, String scope) {
78 if (scope != null) {
79 //when multiple matches are found, find the first one that matches in scope
80 for ( Match match : matches ) {
81 String matchedScope = match.getValue().getScope();
82 if ( matchedScope != null && matchedScope.equals(scope) ) {
83 return match;
84 }
85 }
86 }
87 //since no scope match was found return the first global scopeed match
88 for ( Match match : matches ) {
89 String matchedScope = match.getValue().getScope();
90 if ( matchedScope != null && matchedScope.equals(GLOBAL_SCOPE) ) {
91 return match;
92 }
93 }
94 //return the first match from the list
95 return getMatch(matches, scope);
96 }
97
98 private Match getMatch(List<Match> matches, String scope) {
99 Match match = matches.get(0);
100 String matchedScope = match.getValue().getScope();
101 if (matchedScope != null && scope != null && !matchedScope.equals(scope) && !matchedScope.equals(GLOBAL_SCOPE)) {
102 return null;
103 }
104 return match;
105 }
106
107 /**
108 * Returns a matcher for a given template and processor holder. This method takes into account different scopes in
109 * addition to template values. If a matcher exists for a template but the scope is different, a new matcher is
110 * created and returned.
111 * @param template the template for which a matcher is needed
112 * @param holder the rule holder that goes along with the template.
113 * @return a matcher
114 */
115 private Matcher<UrlRewriteRuleProcessorHolder> getMatcher(Template template, UrlRewriteRuleProcessorHolder holder) {
116 String scope = holder.getScope();
117 if (!matchers.containsKey(scope)) {
118 matchers.put(scope, new Matcher<UrlRewriteRuleProcessorHolder>());
119 }
120
121 return matchers.get(scope);
122 }
123 }