1 /**
2  * Logback: the reliable, generic, fast and flexible logging framework.
3  * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4  *
5  * This program and the accompanying materials are dual-licensed under
6  * either the terms of the Eclipse Public License v1.0 as published by
7  * the Eclipse Foundation
8  *
9  *   or (per the licensee's choosing)
10  *
11  * under the terms of the GNU Lesser General Public License version 2.1
12  * as published by the Free Software Foundation.
13  */

14 package ch.qos.logback.core.joran.spi;
15
16 import java.util.ArrayList;
17 import java.util.List;
18
19 /**
20  * ElementSelector extends {@link ElementPath} with matching operations such as {@link #fullPathMatch(ElementPath)},
21  * {@link #getPrefixMatchLength(ElementPath)} and {@link #getTailMatchLength(ElementPath)}.
22  *
23  * <p>Parts of the path may contain '*' for wildcard matching.
24  *
25  * @author Ceki G&uuml;lc&uuml;
26  * @since 1.1.0
27  */

28 public class ElementSelector extends ElementPath {
29
30     public ElementSelector() {
31         super();
32     }
33
34     public ElementSelector(List<String> list) {
35         super(list);
36     }
37
38     /**
39      * Build an elementPath from a string.
40      *
41      * Note that "/x" is considered equivalent to "x" and to "x/"
42      *
43      */

44     public ElementSelector(String p) {
45         super(p);
46     }
47
48     public boolean fullPathMatch(ElementPath path) {
49         if (path.size() != size()) {
50             return false;
51         }
52
53         int len = size();
54         for (int i = 0; i < len; i++) {
55             if (!equalityCheck(get(i), path.get(i))) {
56                 return false;
57             }
58         }
59         // if everything matches, then the two patterns are equal
60         return true;
61     }
62
63     /**
64      * Returns the number of "tail" components that this pattern has in common
65      * with the pattern p passed as parameter. By "tail" components we mean the
66      * components at the end of the pattern.
67      */

68     public int getTailMatchLength(ElementPath p) {
69         if (p == null) {
70             return 0;
71         }
72
73         int lSize = this.partList.size();
74         int rSize = p.partList.size();
75
76         // no match possible for empty sets
77         if ((lSize == 0) || (rSize == 0)) {
78             return 0;
79         }
80
81         int minLen = (lSize <= rSize) ? lSize : rSize;
82         int match = 0;
83
84         // loop from the end to the front
85         for (int i = 1; i <= minLen; i++) {
86             String l = this.partList.get(lSize - i);
87             String r = p.partList.get(rSize - i);
88
89             if (equalityCheck(l, r)) {
90                 match++;
91             } else {
92                 break;
93             }
94         }
95         return match;
96     }
97
98     public boolean isContainedIn(ElementPath p) {
99         if (p == null) {
100             return false;
101         }
102         return p.toStableString().contains(toStableString());
103     }
104
105     /**
106      * Returns the number of "prefix" components that this pattern has in common
107      * with the pattern p passed as parameter. By "prefix" components we mean the
108      * components at the beginning of the pattern.
109      */

110     public int getPrefixMatchLength(ElementPath p) {
111         if (p == null) {
112             return 0;
113         }
114
115         int lSize = this.partList.size();
116         int rSize = p.partList.size();
117
118         // no match possible for empty sets
119         if ((lSize == 0) || (rSize == 0)) {
120             return 0;
121         }
122
123         int minLen = (lSize <= rSize) ? lSize : rSize;
124         int match = 0;
125
126         for (int i = 0; i < minLen; i++) {
127             String l = this.partList.get(i);
128             String r = p.partList.get(i);
129
130             if (equalityCheck(l, r)) {
131                 match++;
132             } else {
133                 break;
134             }
135         }
136
137         return match;
138     }
139
140     private boolean equalityCheck(String x, String y) {
141         return x.equalsIgnoreCase(y);
142     }
143
144     @Override
145     public boolean equals(Object o) {
146         if ((o == null) || !(o instanceof ElementSelector)) {
147             return false;
148         }
149
150         ElementSelector r = (ElementSelector) o;
151
152         if (r.size() != size()) {
153             return false;
154         }
155
156         int len = size();
157
158         for (int i = 0; i < len; i++) {
159             if (!equalityCheck(get(i), r.get(i))) {
160                 return false;
161             }
162         }
163
164         // if everything matches, then the two patterns are equal
165         return true;
166     }
167
168     @Override
169     public int hashCode() {
170         int hc = 0;
171         int len = size();
172
173         for (int i = 0; i < len; i++) {
174             // make Pattern comparisons case insensitive
175             // http://jira.qos.ch/browse/LBCORE-76
176             hc ^= get(i).toLowerCase().hashCode();
177         }
178         return hc;
179     }
180
181 }
182