001/* 002 * Copyright 2008-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2018 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.ldap.matchingrules; 022 023 024 025import com.unboundid.asn1.ASN1OctetString; 026import com.unboundid.ldap.sdk.LDAPException; 027import com.unboundid.util.Debug; 028import com.unboundid.util.Extensible; 029import com.unboundid.util.ThreadSafety; 030import com.unboundid.util.ThreadSafetyLevel; 031 032 033 034/** 035 * This class provides a common matching rule framework that may be extended by 036 * matching rule implementations in which equality, ordering, and substring 037 * matching can all be made based on byte-for-byte comparisons of the normalized 038 * value, for values that are considered acceptable by the 039 * {@link MatchingRule#normalize} and {@link MatchingRule#normalizeSubstring} 040 * methods. 041 */ 042@Extensible() 043@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 044public abstract class SimpleMatchingRule 045 extends MatchingRule 046{ 047 /** 048 * The serial version UID for this serializable class. 049 */ 050 private static final long serialVersionUID = -7221506185552250694L; 051 052 053 054 /** 055 * {@inheritDoc} 056 */ 057 @Override() 058 public boolean valuesMatch(final ASN1OctetString value1, 059 final ASN1OctetString value2) 060 throws LDAPException 061 { 062 return normalize(value1).equals(normalize(value2)); 063 } 064 065 066 067 /** 068 * {@inheritDoc} 069 */ 070 @Override() 071 public boolean matchesAnyValue(final ASN1OctetString assertionValue, 072 final ASN1OctetString[] attributeValues) 073 throws LDAPException 074 { 075 if ((assertionValue == null) || (attributeValues == null) || 076 (attributeValues.length == 0)) 077 { 078 return false; 079 } 080 081 final ASN1OctetString normalizedAssertionValue = normalize(assertionValue); 082 083 for (final ASN1OctetString attributeValue : attributeValues) 084 { 085 try 086 { 087 if (normalizedAssertionValue.equalsIgnoreType( 088 normalize(attributeValue))) 089 { 090 return true; 091 } 092 } 093 catch (final Exception e) 094 { 095 Debug.debugException(e); 096 } 097 } 098 099 return false; 100 } 101 102 103 104 /** 105 * {@inheritDoc} 106 */ 107 @Override() 108 public boolean matchesSubstring(final ASN1OctetString value, 109 final ASN1OctetString subInitial, 110 final ASN1OctetString[] subAny, 111 final ASN1OctetString subFinal) 112 throws LDAPException 113 { 114 final byte[] normValue = normalize(value).getValue(); 115 116 int pos = 0; 117 if (subInitial != null) 118 { 119 final byte[] normSubInitial = 120 normalizeSubstring(subInitial, SUBSTRING_TYPE_SUBINITIAL).getValue(); 121 if (normValue.length < normSubInitial.length) 122 { 123 return false; 124 } 125 126 for (int i=0; i < normSubInitial.length; i++) 127 { 128 if (normValue[i] != normSubInitial[i]) 129 { 130 return false; 131 } 132 } 133 134 pos = normSubInitial.length; 135 } 136 137 if (subAny != null) 138 { 139 final byte[][] normSubAny = new byte[subAny.length][]; 140 for (int i=0; i < subAny.length; i++) 141 { 142 normSubAny[i] = 143 normalizeSubstring(subAny[i],SUBSTRING_TYPE_SUBANY).getValue(); 144 } 145 146 for (final byte[] b : normSubAny) 147 { 148 if (b.length == 0) 149 { 150 continue; 151 } 152 153 boolean match = false; 154 final int subEndLength = normValue.length - b.length; 155 while (pos <= subEndLength) 156 { 157 match = true; 158 for (int i=0; i < b.length; i++) 159 { 160 if (normValue[pos+i] != b[i]) 161 { 162 match = false; 163 break; 164 } 165 } 166 167 if (match) 168 { 169 pos += b.length; 170 break; 171 } 172 else 173 { 174 pos++; 175 } 176 } 177 178 if (! match) 179 { 180 return false; 181 } 182 } 183 } 184 185 if (subFinal != null) 186 { 187 final byte[] normSubFinal = 188 normalizeSubstring(subFinal, SUBSTRING_TYPE_SUBFINAL).getValue(); 189 int finalStartPos = normValue.length - normSubFinal.length; 190 if (finalStartPos < pos) 191 { 192 return false; 193 } 194 195 for (int i=0; i < normSubFinal.length; i++,finalStartPos++) 196 { 197 if (normValue[finalStartPos] != normSubFinal[i]) 198 { 199 return false; 200 } 201 } 202 } 203 204 return true; 205 } 206 207 208 209 /** 210 * {@inheritDoc} 211 */ 212 @Override() 213 public int compareValues(final ASN1OctetString value1, 214 final ASN1OctetString value2) 215 throws LDAPException 216 { 217 final byte[] normValue1 = normalize(value1).getValue(); 218 final byte[] normValue2 = normalize(value2).getValue(); 219 220 final int minLength = Math.min(normValue1.length, normValue2.length); 221 for (int i=0; i < minLength; i++) 222 { 223 final int b1 = normValue1[i] & 0xFF; 224 final int b2 = normValue2[i] & 0xFF; 225 226 if (b1 < b2) 227 { 228 return -1; 229 } 230 else if (b1 > b2) 231 { 232 return 1; 233 } 234 } 235 236 // If we've gotten here, then it means that all of the bytes they had in 237 // common are the same. At this point, the shorter of the two should be 238 // ordered first, or return zero if they're the same length. 239 return normValue1.length - normValue2.length; 240 } 241}