001/* 002 * Copyright 2008-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2017 UnboundID Corp. 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.Extensible; 028import com.unboundid.util.ThreadSafety; 029import com.unboundid.util.ThreadSafetyLevel; 030 031 032 033/** 034 * This class provides a common matching rule framework that may be extended by 035 * matching rule implementations in which equality, ordering, and substring 036 * matching can all be made based on byte-for-byte comparisons of the normalized 037 * value, for values that are considered acceptable by the 038 * {@link MatchingRule#normalize} and {@link MatchingRule#normalizeSubstring} 039 * methods. 040 */ 041@Extensible() 042@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 043public abstract class SimpleMatchingRule 044 extends MatchingRule 045{ 046 /** 047 * The serial version UID for this serializable class. 048 */ 049 private static final long serialVersionUID = -7221506185552250694L; 050 051 052 053 /** 054 * {@inheritDoc} 055 */ 056 @Override() 057 public boolean valuesMatch(final ASN1OctetString value1, 058 final ASN1OctetString value2) 059 throws LDAPException 060 { 061 return normalize(value1).equals(normalize(value2)); 062 } 063 064 065 066 /** 067 * {@inheritDoc} 068 */ 069 @Override() 070 public boolean matchesSubstring(final ASN1OctetString value, 071 final ASN1OctetString subInitial, 072 final ASN1OctetString[] subAny, 073 final ASN1OctetString subFinal) 074 throws LDAPException 075 { 076 final byte[] normValue = normalize(value).getValue(); 077 078 int pos = 0; 079 if (subInitial != null) 080 { 081 final byte[] normSubInitial = 082 normalizeSubstring(subInitial, SUBSTRING_TYPE_SUBINITIAL).getValue(); 083 if (normValue.length < normSubInitial.length) 084 { 085 return false; 086 } 087 088 for (int i=0; i < normSubInitial.length; i++) 089 { 090 if (normValue[i] != normSubInitial[i]) 091 { 092 return false; 093 } 094 } 095 096 pos = normSubInitial.length; 097 } 098 099 if (subAny != null) 100 { 101 final byte[][] normSubAny = new byte[subAny.length][]; 102 for (int i=0; i < subAny.length; i++) 103 { 104 normSubAny[i] = 105 normalizeSubstring(subAny[i],SUBSTRING_TYPE_SUBANY).getValue(); 106 } 107 108 for (final byte[] b : normSubAny) 109 { 110 if (b.length == 0) 111 { 112 continue; 113 } 114 115 boolean match = false; 116 final int subEndLength = normValue.length - b.length; 117 while (pos <= subEndLength) 118 { 119 match = true; 120 for (int i=0; i < b.length; i++) 121 { 122 if (normValue[pos+i] != b[i]) 123 { 124 match = false; 125 break; 126 } 127 } 128 129 if (match) 130 { 131 pos += b.length; 132 break; 133 } 134 else 135 { 136 pos++; 137 } 138 } 139 140 if (! match) 141 { 142 return false; 143 } 144 } 145 } 146 147 if (subFinal != null) 148 { 149 final byte[] normSubFinal = 150 normalizeSubstring(subFinal, SUBSTRING_TYPE_SUBFINAL).getValue(); 151 int finalStartPos = normValue.length - normSubFinal.length; 152 if (finalStartPos < pos) 153 { 154 return false; 155 } 156 157 for (int i=0; i < normSubFinal.length; i++,finalStartPos++) 158 { 159 if (normValue[finalStartPos] != normSubFinal[i]) 160 { 161 return false; 162 } 163 } 164 } 165 166 return true; 167 } 168 169 170 171 /** 172 * {@inheritDoc} 173 */ 174 @Override() 175 public int compareValues(final ASN1OctetString value1, 176 final ASN1OctetString value2) 177 throws LDAPException 178 { 179 final byte[] normValue1 = normalize(value1).getValue(); 180 final byte[] normValue2 = normalize(value2).getValue(); 181 182 final int minLength = Math.min(normValue1.length, normValue2.length); 183 for (int i=0; i < minLength; i++) 184 { 185 final int b1 = normValue1[i] & 0xFF; 186 final int b2 = normValue2[i] & 0xFF; 187 188 if (b1 < b2) 189 { 190 return -1; 191 } 192 else if (b1 > b2) 193 { 194 return 1; 195 } 196 } 197 198 // If we've gotten here, then it means that all of the bytes they had in 199 // common are the same. At this point, the shorter of the two should be 200 // ordered first, or return zero if they're the same length. 201 return normValue1.length - normValue2.length; 202 } 203}