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ülcü
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