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