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