001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *  
010 *    https://www.apache.org/licenses/LICENSE-2.0
011 *  
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License. 
018 *  
019 */
020package org.apache.directory.api.ldap.model.filter;
021
022
023import java.util.Arrays;
024
025import org.apache.directory.api.i18n.I18n;
026import org.apache.directory.api.ldap.model.constants.SchemaConstants;
027import org.apache.directory.api.ldap.model.entry.Value;
028import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
029import org.apache.directory.api.ldap.model.schema.AttributeType;
030import org.apache.directory.api.util.Strings;
031
032
033/**
034 * A simple assertion value node.
035 * 
036 * @param <T> The Value type
037 * 
038 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
039 */
040public abstract class SimpleNode<T> extends LeafNode
041{
042    /** the value */
043    protected Value value;
044    
045    /** The value as a byte[] */
046    protected byte[] bytes;
047
048    /** Constants for comparisons : @gt; */
049    public static final boolean EVAL_GREATER = true;
050
051    /** Constants for comparisons : &lt; */
052    public static final boolean EVAL_LESSER = false;
053
054
055    /**
056     * Creates a new SimpleNode object.
057     * 
058     * @param attribute the attribute name
059     * @param bytes the data to inject
060     * @param assertionType the type of assertion represented by this ExprNode
061     */
062    protected SimpleNode( String attribute, byte[] bytes, AssertionType assertionType )
063    {
064        super( attribute, assertionType );
065        this.bytes = bytes;
066    }
067
068
069    /**
070     * Creates a new SimpleNode object.
071     * 
072     * @param attributeType the attribute name
073     * @param bytes the data to inject
074     * @param assertionType the type of assertion represented by this ExprNode
075     */
076    protected SimpleNode( AttributeType attributeType, byte[] bytes, AssertionType assertionType )
077    {
078        super( attributeType, assertionType );
079        this.bytes = bytes;
080        
081        try
082        {
083            if ( attributeType.isHR() )
084            {
085                value = new Value( attributeType, Strings.utf8ToString( bytes ) );
086            }
087            else
088            {
089                    value = new Value( attributeType, bytes );
090            }
091        }
092        catch ( LdapInvalidAttributeValueException e )
093        {
094            throw new RuntimeException( e.getMessage() );
095        }
096    }
097
098
099    /**
100     * Creates a new SimpleNode object.
101     * 
102     * @param attribute the attribute name
103     * @param string the value to inject
104     * @param assertionType the type of assertion represented by this ExprNode
105     */
106    protected SimpleNode( String attribute, String string, AssertionType assertionType )
107    {
108        super( attribute, assertionType );
109        bytes = Strings.getBytesUtf8( string );
110        
111        if ( attributeType != null )
112        {
113            try
114            {
115                if ( attributeType.isHR() )
116                {
117                    value = new Value( attributeType, string );
118                }
119                else
120                {
121                    value = new Value( attributeType, bytes );
122                }
123            }
124            catch ( LdapInvalidAttributeValueException e )
125            {
126                throw new RuntimeException( e.getMessage() );
127            }
128        }
129    }
130
131
132    /**
133     * Creates a new SimpleNode object.
134     * 
135     * @param attributeType the attribute name
136     * @param value the value to test for
137     * @param assertionType the type of assertion represented by this ExprNode
138     */
139    protected SimpleNode( AttributeType attributeType, Value value, AssertionType assertionType )
140    {
141        super( attributeType, assertionType );
142        this.value = value;
143    }
144
145
146    /**
147     * Makes a full clone in new memory space of the current node and children
148     */
149    @SuppressWarnings("unchecked")
150    @Override
151    public ExprNode clone()
152    {
153        ExprNode clone = super.clone();
154
155        // Clone the value, if we have one
156        if ( value != null )
157        {
158            ( ( SimpleNode<T> ) clone ).value = value.clone();
159        }
160        else
161        {
162            // clone the bytes if any
163            if ( bytes != null )
164            {
165                ( ( SimpleNode<T> ) clone ).bytes = new byte[bytes.length];
166                System.arraycopy( bytes, 0, ( ( SimpleNode<T> ) clone ).bytes, 0, bytes.length );
167            }
168        }
169
170        return clone;
171    }
172
173
174    /**
175     * Gets the value.
176     * 
177     * @return the value
178     */
179    public final Value getValue()
180    {
181        if ( value == null )
182        {
183            return new Value( bytes );
184        }
185        else
186        {
187            return value;
188        }
189    }
190
191
192    /** 
193     * @return representation of value, escaped for use in a filter if required 
194     */
195    public String getEscapedValue()
196    {
197        if ( value != null )
198        {
199            return escapeFilterValue( value.getAttributeType(), value.getBytes() );
200        }
201        else
202        {
203            return escapeFilterValue( null, bytes );
204        }
205    }
206
207
208    /**
209     * Sets the value of this node.
210     * 
211     * @param value the value for this node
212     */
213    public void setValue( Value value )
214    {
215        this.value = value;
216        this.bytes = value.getBytes();
217    }
218
219
220    /**
221     * Pretty prints this expression node along with annotation information.
222     *
223     * @param buf the buffer to print into
224     * @return the same buf argument returned for call chaining
225     */
226    public StringBuilder printToBuffer( StringBuilder buf )
227    {
228        if ( ( null != getAnnotations() ) && getAnnotations().containsKey( "count" ) )
229        {
230            buf.append( ":[" );
231            buf.append( getAnnotations().get( "count" ).toString() );
232            buf.append( "] " );
233        }
234
235        buf.append( ')' );
236
237        return buf;
238    }
239
240
241    /**
242     * @see ExprNode#printRefinementToBuffer(StringBuilder)
243     * @return The buffer in which the refinement has been appended
244     * @throws UnsupportedOperationException if this node isn't a part of a refinement.
245     */
246    @Override
247    public StringBuilder printRefinementToBuffer( StringBuilder buf )
248    {
249        if ( isSchemaAware() )
250        {
251            if ( !attributeType.getOid().equals( SchemaConstants.OBJECT_CLASS_AT_OID ) )
252            {
253                throw new UnsupportedOperationException( I18n.err( I18n.ERR_13318_INVALID_ATTR_IN_REFINEMENT, attribute ) );
254            }
255        }
256        else
257        {
258            if ( ( attribute == null )
259                || !( SchemaConstants.OBJECT_CLASS_AT.equalsIgnoreCase( attribute )
260                || SchemaConstants.OBJECT_CLASS_AT_OID.equalsIgnoreCase( attribute ) ) )
261            {
262                throw new UnsupportedOperationException( I18n.err( I18n.ERR_13318_INVALID_ATTR_IN_REFINEMENT, attribute ) );
263            }
264        }
265
266        buf.append( "item: " ).append( value );
267
268        return buf;
269    }
270
271
272    /**
273     * @see Object#hashCode()
274     * @return the instance's hash code 
275     */
276    @Override
277    public int hashCode()
278    {
279        int h = 37;
280
281        h = h * 17 + super.hashCode();
282        h = h * 17 + ( value == null ? 0 : value.hashCode() );
283
284        return h;
285    }
286
287
288    /**
289     * @see java.lang.Object#equals(java.lang.Object)
290     */
291    @Override
292    public boolean equals( Object other )
293    {
294        if ( this == other )
295        {
296            return true;
297        }
298
299        if ( !( other instanceof SimpleNode<?> ) )
300        {
301            return false;
302        }
303
304        if ( other.getClass() != this.getClass() )
305        {
306            return false;
307        }
308
309        if ( !super.equals( other ) )
310        {
311            return false;
312        }
313
314        SimpleNode<?> otherNode = ( SimpleNode<?> ) other;
315
316        if ( value == null )
317        {
318            if ( bytes == null )
319            {
320                return otherNode.bytes == null;
321            }
322            else
323            {
324                return Arrays.equals( bytes,  otherNode.bytes );
325            }
326        }
327        else
328        {
329            return value.equals( otherNode.value );
330        }
331    }
332}