001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core.joran.spi; 015 016import java.util.List; 017 018/** 019 * ElementSelector extends {@link ElementPath} with matching operations such as 020 * {@link #fullPathMatch(ElementPath)}, 021 * {@link #getPrefixMatchLength(ElementPath)} and 022 * {@link #getTailMatchLength(ElementPath)}. 023 * 024 * <p> 025 * Parts of the path may contain '*' for wildcard matching. 026 * 027 * @author Ceki Gülcü 028 * @since 1.1.0 029 */ 030public class ElementSelector extends ElementPath { 031 032 public ElementSelector() { 033 super(); 034 } 035 036 public ElementSelector(List<String> list) { 037 super(list); 038 } 039 040 /** 041 * Build an elementPath from a string. 042 * 043 * Note that "/x" is considered equivalent to "x" and to "x/" 044 * 045 */ 046 public ElementSelector(String p) { 047 super(p); 048 } 049 050 public boolean fullPathMatch(ElementPath path) { 051 if (path.size() != size()) { 052 return false; 053 } 054 055 int len = size(); 056 for (int i = 0; i < len; i++) { 057 if (!equalityCheck(get(i), path.get(i))) { 058 return false; 059 } 060 } 061 // if everything matches, then the two patterns are equal 062 return true; 063 } 064 065 /** 066 * Returns the number of "tail" components that this pattern has in common with 067 * the pattern p passed as parameter. By "tail" components we mean the 068 * components at the end of the pattern. 069 */ 070 public int getTailMatchLength(ElementPath p) { 071 if (p == null) { 072 return 0; 073 } 074 075 int lSize = this.partList.size(); 076 int rSize = p.partList.size(); 077 078 // no match possible for empty sets 079 if ((lSize == 0) || (rSize == 0)) { 080 return 0; 081 } 082 083 int minLen = (lSize <= rSize) ? lSize : rSize; 084 int match = 0; 085 086 // loop from the end to the front 087 for (int i = 1; i <= minLen; i++) { 088 String l = this.partList.get(lSize - i); 089 String r = p.partList.get(rSize - i); 090 091 if (equalityCheck(l, r)) { 092 match++; 093 } else { 094 break; 095 } 096 } 097 return match; 098 } 099 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}