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 *    http://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.shared.ldap.model.entry;
021
022import java.io.IOException;
023import java.io.ObjectInput;
024import java.io.ObjectOutput;
025
026import org.apache.directory.shared.i18n.I18n;
027import org.apache.directory.shared.ldap.model.exception.LdapException;
028import org.apache.directory.shared.ldap.model.exception.LdapInvalidAttributeValueException;
029import org.apache.directory.shared.ldap.model.schema.AttributeType;
030import org.apache.directory.shared.ldap.model.schema.SchemaManager;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034/**
035 * An internal implementation for a ModificationItem. The name has been
036 * chosen so that it does not conflict with @see ModificationItem
037 *
038 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
039 */
040public class DefaultModification implements Modification
041{
042    /** The modification operation */
043    private ModificationOperation operation;
044    
045    /** The attribute which contains the modification */
046    private Attribute attribute;
047    
048    /** The AtributeType */
049    private AttributeType attributeType;
050 
051    /** logger for reporting errors that might not be handled properly upstream */
052    protected static final Logger LOG = LoggerFactory.getLogger( Modification.class );
053
054    
055    /**
056     * Creates a new instance of DefaultModification.
057     */
058    public DefaultModification()
059    {
060    }
061
062    
063    /**
064     * Creates a new instance of DefaultModification.
065     *
066     * @param operation The modification operation
067     * @param attribute The associated attribute 
068     */
069    public DefaultModification( ModificationOperation operation, Attribute attribute )
070    {
071        this.operation = operation;
072        this.attribute = attribute;
073    }
074
075
076    /**
077     * Creates a new instance of DefaultModification.
078     *
079     * @param operation The modification operation
080     * @param attributeId The associated attribute ID
081     * @param values the associated values
082     */
083    public DefaultModification( ModificationOperation operation, String attributeId, String... values )
084    {
085        this.operation = operation;
086        this.attribute = new DefaultAttribute( attributeId, values );
087    }
088
089
090    /**
091     * Creates a new instance of DefaultModification.
092     *
093     * @param operation The modification operation
094     * @param attributeId The associated attribute ID
095     * @param values the associated values
096     */
097    public DefaultModification( ModificationOperation operation, String attributeId, byte[]... values )
098    {
099        this.operation = operation;
100        this.attribute = new DefaultAttribute( attributeId, values );
101    }
102
103
104    /**
105     * Creates a new instance of DefaultModification.
106     *
107     * @param operation The modification operation
108     * @param attributeId The associated attribute ID
109     * @param values the associated values
110     */
111    public DefaultModification( ModificationOperation operation, String attributeId, Value<?>... values )
112    {
113        this.operation = operation;
114        this.attribute = new DefaultAttribute( attributeId, values );
115    }
116
117
118    /**
119     * Creates a new instance of DefaultModification with no value
120     *
121     * @param operation The modification operation
122     * @param attributeId The associated attribute ID
123     */
124    public DefaultModification( ModificationOperation operation, String attributeId )
125    {
126        this.operation = operation;
127        this.attribute = new DefaultAttribute( attributeId );
128    }
129
130
131    /**
132     * Creates a new instance of DefaultModification.
133     *
134     * @param operation The modification operation
135     * @param attributeType The associated attributeType
136     * @param values the associated values
137     */
138    public DefaultModification( ModificationOperation operation, AttributeType attributeType, String... values ) 
139        throws LdapInvalidAttributeValueException
140    {
141        this.operation = operation;
142        this.attribute = new DefaultAttribute( attributeType, values );
143    }
144
145
146    /**
147     * Creates a new instance of DefaultModification.
148     *
149     * @param operation The modification operation
150     * @param attributeType The associated attributeType
151     * @param values the associated values
152     */
153    public DefaultModification( ModificationOperation operation, AttributeType attributeType, byte[]... values )
154    throws LdapInvalidAttributeValueException
155    {
156        this.operation = operation;
157        this.attribute = new DefaultAttribute( attributeType, values );
158    }
159
160
161    /**
162     * Creates a new instance of DefaultModification.
163     *
164     * @param operation The modification operation
165     * @param attributeType The associated attributeType
166     * @param values the associated values
167     */
168    public DefaultModification( ModificationOperation operation, AttributeType attributeType, Value<?>... values )
169    throws LdapInvalidAttributeValueException
170    {
171        this.operation = operation;
172        this.attribute = new DefaultAttribute( attributeType, values );
173    }
174
175
176    /**
177     * Creates a new instance of DefaultModification with no value.
178     *
179     * @param operation The modification operation
180     * @param attributeType The associated attributeType
181     */
182    public DefaultModification( ModificationOperation operation, AttributeType attributeType )
183    throws LdapInvalidAttributeValueException
184    {
185        this.operation = operation;
186        this.attribute = new DefaultAttribute( attributeType );
187    }
188
189
190    /**
191     * Creates a new instance of DefaultModification.
192     *
193     * @param schemaManager The schema manager 
194     * @param modification The modification
195     */
196    public DefaultModification( SchemaManager schemaManager, Modification modification )
197    {
198        operation = modification.getOperation();
199        
200        Attribute modAttribute = modification.getAttribute();
201        
202        try
203        {
204            AttributeType at = modAttribute.getAttributeType();
205            
206            if ( at == null )
207            {
208                at = schemaManager.lookupAttributeTypeRegistry( modAttribute.getId() );
209            }
210            
211            attribute = new DefaultAttribute( at, modAttribute );
212        }
213        catch ( LdapException ne )
214        {
215            // The attributeType is incorrect. Log, but do nothing otherwise.
216            LOG.error( I18n.err( I18n.ERR_04472, modAttribute.getId() ) );
217        }
218    }
219    
220    
221    /**
222     * {@inheritDoc}
223     */
224    public ModificationOperation getOperation()
225    {
226        return operation;
227    }
228    
229    
230    /**
231     * {@inheritDoc}
232     */
233    public void setOperation( int operation )
234    {
235        this.operation = ModificationOperation.getOperation( operation );
236    }
237
238    
239    /**
240     * {@inheritDoc}
241     */
242    public void setOperation( ModificationOperation operation )
243    {
244        this.operation = operation;
245    }
246        
247    
248    /**
249     * {@inheritDoc}
250     */
251    public Attribute getAttribute()
252    {
253        return attribute;
254    }
255    
256    
257    /**
258     * {@inheritDoc}
259     */
260    public void setAttribute( Attribute attribute )
261    {
262        this.attribute = attribute;
263    }
264    
265    
266    /**
267     * {@inheritDoc}
268     */
269    public void apply( AttributeType attributeType ) throws LdapInvalidAttributeValueException
270    {
271        this.attributeType = attributeType;
272        
273        if ( attribute != null )
274        {
275            attribute.apply( attributeType );
276        }
277    }
278
279
280    /**
281     * {@inheritDoc}
282     */
283    public AttributeType getAttributeType()
284    {
285        return attributeType;
286    }
287    
288    
289    /**
290     * @see Object#equals(Object)
291     * @return <code>true</code> if both values are equal
292     */
293    public boolean equals( Object that )
294    {
295        // Basic equals checks
296        if ( this == that )
297        {
298            return true;
299        }
300        
301        if ( ! (that instanceof Modification ) )
302        {
303            return false;
304        }
305        
306        Modification otherModification = (Modification)that;
307        
308        // Check the operation
309        if ( operation != otherModification.getOperation() )
310        {
311            return false;
312        }
313
314        // Check the attribute
315        if ( attribute == null )
316        {
317            return otherModification.getAttribute() == null;
318        }
319        
320        return attribute.equals( otherModification.getAttribute() );
321    }
322    
323    
324    /**
325     * Compute the modification @see Object#hashCode
326     * @return the instance's hash code 
327     */
328    public int hashCode()
329    {
330        int h = 37;
331        
332        h += h*17 + operation.getValue();
333        h += h*17 + attribute.hashCode();
334        
335        return h;
336    }
337    
338
339    /**
340     * @see java.io.Externalizable#readExternal(ObjectInput)
341     */
342    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
343    {
344        // The operation
345        operation = ModificationOperation.getOperation( in.readInt() );
346
347        // The EntryAttribute if we have some
348        boolean hasAttribute = in.readBoolean();
349        
350        if ( hasAttribute )
351        {
352            attribute = new DefaultAttribute();
353            attribute.readExternal( in );
354        }
355    }
356    
357    
358    /**
359     * @see java.io.Externalizable#writeExternal(ObjectOutput)
360     */
361    public void writeExternal( ObjectOutput out ) throws IOException
362    {
363        // The operation
364        out.writeInt( operation.getValue() );
365        
366        // The EntryAttribute if not null
367        if ( attribute != null )
368        {
369            out.writeBoolean( true );
370            attribute.writeExternal( out );
371        }
372        else
373        {
374            out.writeBoolean( false );
375        }
376        
377        out.flush();
378    }
379    
380    
381    /**
382     * {@inheritDoc}
383     */
384    public DefaultModification clone()
385    {
386        try
387        {
388            DefaultModification clone = (DefaultModification)super.clone();
389            
390            clone.attribute = this.attribute.clone();
391            return clone;
392        }
393        catch ( CloneNotSupportedException cnse )
394        {
395            return null;
396        }
397    }
398    
399    
400    /**
401     * @see Object#toString()
402     */
403    public String toString()
404    {
405        StringBuilder sb = new StringBuilder();
406        
407        sb.append( "Modification: " ).
408            append( operation ).
409            append( "\n" ).
410            append( ", attribute : " ).
411            append( attribute );
412        
413        return sb.toString();
414    }
415}