001    /*
002     * Copyright 2008-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2015 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     */
021    package com.unboundid.ldap.matchingrules;
022    
023    
024    
025    import com.unboundid.asn1.ASN1OctetString;
026    import com.unboundid.ldap.sdk.LDAPException;
027    import com.unboundid.util.Extensible;
028    import com.unboundid.util.ThreadSafety;
029    import 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)
043    public 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    }