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.List;
17
18 /**
19 * ElementSelector extends {@link ElementPath} with matching operations such as
20 * {@link #fullPathMatch(ElementPath)},
21 * {@link #getPrefixMatchLength(ElementPath)} and
22 * {@link #getTailMatchLength(ElementPath)}.
23 *
24 * <p>
25 * Parts of the path may contain '*' for wildcard matching.
26 *
27 * @author Ceki Gülcü
28 * @since 1.1.0
29 */
30 public class ElementSelector extends ElementPath {
31
32 public ElementSelector() {
33 super();
34 }
35
36 public ElementSelector(List<String> list) {
37 super(list);
38 }
39
40 /**
41 * Build an elementPath from a string.
42 *
43 * Note that "/x" is considered equivalent to "x" and to "x/"
44 *
45 */
46 public ElementSelector(String p) {
47 super(p);
48 }
49
50 public boolean fullPathMatch(ElementPath path) {
51 if (path.size() != size()) {
52 return false;
53 }
54
55 int len = size();
56 for (int i = 0; i < len; i++) {
57 if (!equalityCheck(get(i), path.get(i))) {
58 return false;
59 }
60 }
61 // if everything matches, then the two patterns are equal
62 return true;
63 }
64
65 /**
66 * Returns the number of "tail" components that this pattern has in common with
67 * the pattern p passed as parameter. By "tail" components we mean the
68 * components at the end of the pattern.
69 */
70 public int getTailMatchLength(ElementPath p) {
71 if (p == null) {
72 return 0;
73 }
74
75 int lSize = this.partList.size();
76 int rSize = p.partList.size();
77
78 // no match possible for empty sets
79 if ((lSize == 0) || (rSize == 0)) {
80 return 0;
81 }
82
83 int minLen = (lSize <= rSize) ? lSize : rSize;
84 int match = 0;
85
86 // loop from the end to the front
87 for (int i = 1; i <= minLen; i++) {
88 String l = this.partList.get(lSize - i);
89 String r = p.partList.get(rSize - i);
90
91 if (equalityCheck(l, r)) {
92 match++;
93 } else {
94 break;
95 }
96 }
97 return match;
98 }
99
100 public boolean isContainedIn(ElementPath p) {
101 if (p == null) {
102 return false;
103 }
104 return p.toStableString().contains(toStableString());
105 }
106
107 /**
108 * Returns the number of "prefix" components that this pattern has in common
109 * with the pattern p passed as parameter. By "prefix" components we mean the
110 * components at the beginning of the pattern.
111 */
112 public int getPrefixMatchLength(ElementPath p) {
113 if (p == null) {
114 return 0;
115 }
116
117 int lSize = this.partList.size();
118 int rSize = p.partList.size();
119
120 // no match possible for empty sets
121 if ((lSize == 0) || (rSize == 0)) {
122 return 0;
123 }
124
125 int minLen = (lSize <= rSize) ? lSize : rSize;
126 int match = 0;
127
128 for (int i = 0; i < minLen; i++) {
129 String l = this.partList.get(i);
130 String r = p.partList.get(i);
131
132 if (equalityCheck(l, r)) {
133 match++;
134 } else {
135 break;
136 }
137 }
138
139 return match;
140 }
141
142 private boolean equalityCheck(String x, String y) {
143 return x.equalsIgnoreCase(y);
144 }
145
146 @Override
147 public boolean equals(Object o) {
148 if ((o == null) || !(o instanceof ElementSelector)) {
149 return false;
150 }
151
152 ElementSelector r = (ElementSelector) o;
153
154 if (r.size() != size()) {
155 return false;
156 }
157
158 int len = size();
159
160 for (int i = 0; i < len; i++) {
161 if (!equalityCheck(get(i), r.get(i))) {
162 return false;
163 }
164 }
165
166 // if everything matches, then the two patterns are equal
167 return true;
168 }
169
170 @Override
171 public int hashCode() {
172 int hc = 0;
173 int len = size();
174
175 for (int i = 0; i < len; i++) {
176 // make Pattern comparisons case insensitive
177 // http://jira.qos.ch/browse/LBCORE-76
178 hc ^= get(i).toLowerCase().hashCode();
179 }
180 return hc;
181 }
182
183 }