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     */
140    public DefaultModification( ModificationOperation operation, AttributeType attributeType, String... values )
141        throws LdapInvalidAttributeValueException
142    {
143        this.operation = operation;
144        this.attribute = new DefaultAttribute( attributeType, values );
145    }
146
147
148    /**
149     * Creates a new instance of DefaultModification.
150     *
151     * @param operation The modification operation
152     * @param attributeType The associated attributeType
153     * @param values the associated values
154     */
155    public DefaultModification( ModificationOperation operation, AttributeType attributeType, byte[]... values )
156        throws LdapInvalidAttributeValueException
157    {
158        this.operation = operation;
159        this.attribute = new DefaultAttribute( attributeType, values );
160    }
161
162
163    /**
164     * Creates a new instance of DefaultModification.
165     *
166     * @param operation The modification operation
167     * @param attributeType The associated attributeType
168     * @param values the associated values
169     */
170    public DefaultModification( ModificationOperation operation, AttributeType attributeType, Value<?>... values )
171        throws LdapInvalidAttributeValueException
172    {
173        this.operation = operation;
174        this.attribute = new DefaultAttribute( attributeType, values );
175    }
176
177
178    /**
179     * Creates a new instance of DefaultModification with no value.
180     *
181     * @param operation The modification operation
182     * @param attributeType The associated attributeType
183     */
184    public DefaultModification( ModificationOperation operation, AttributeType attributeType )
185        throws LdapInvalidAttributeValueException
186    {
187        this.operation = operation;
188        this.attribute = new DefaultAttribute( attributeType );
189    }
190
191
192    /**
193     * Creates a new instance of DefaultModification.
194     *
195     * @param schemaManager The schema manager 
196     * @param modification The modification
197     */
198    public DefaultModification( SchemaManager schemaManager, Modification modification )
199    {
200        operation = modification.getOperation();
201
202        Attribute modAttribute = modification.getAttribute();
203
204        try
205        {
206            AttributeType at = modAttribute.getAttributeType();
207
208            if ( at == null )
209            {
210                at = schemaManager.lookupAttributeTypeRegistry( modAttribute.getId() );
211            }
212
213            attribute = new DefaultAttribute( at, modAttribute );
214        }
215        catch ( LdapException ne )
216        {
217            // The attributeType is incorrect. Log, but do nothing otherwise.
218            LOG.error( I18n.err( I18n.ERR_04472, modAttribute.getId() ) );
219        }
220    }
221
222
223    /**
224     * {@inheritDoc}
225     */
226    public ModificationOperation getOperation()
227    {
228        return operation;
229    }
230
231
232    /**
233     * {@inheritDoc}
234     */
235    public void setOperation( int operation )
236    {
237        this.operation = ModificationOperation.getOperation( operation );
238    }
239
240
241    /**
242     * {@inheritDoc}
243     */
244    public void setOperation( ModificationOperation operation )
245    {
246        this.operation = operation;
247    }
248
249
250    /**
251     * {@inheritDoc}
252     */
253    public Attribute getAttribute()
254    {
255        return attribute;
256    }
257
258
259    /**
260     * {@inheritDoc}
261     */
262    public void setAttribute( Attribute attribute )
263    {
264        this.attribute = attribute;
265    }
266
267
268    /**
269     * {@inheritDoc}
270     */
271    public void apply( AttributeType attributeType ) throws LdapInvalidAttributeValueException
272    {
273        this.attributeType = attributeType;
274
275        if ( attribute != null )
276        {
277            attribute.apply( attributeType );
278        }
279    }
280
281
282    /**
283     * {@inheritDoc}
284     */
285    public AttributeType getAttributeType()
286    {
287        return attributeType;
288    }
289
290
291    /**
292     * @see Object#equals(Object)
293     * @return <code>true</code> if both values are equal
294     */
295    public boolean equals( Object that )
296    {
297        // Basic equals checks
298        if ( this == that )
299        {
300            return true;
301        }
302
303        if ( !( that instanceof Modification ) )
304        {
305            return false;
306        }
307
308        Modification otherModification = ( Modification ) that;
309
310        // Check the operation
311        if ( operation != otherModification.getOperation() )
312        {
313            return false;
314        }
315
316        // Check the attribute
317        if ( attribute == null )
318        {
319            return otherModification.getAttribute() == null;
320        }
321
322        return attribute.equals( otherModification.getAttribute() );
323    }
324
325
326    /**
327     * Compute the modification @see Object#hashCode
328     * @return the instance's hash code 
329     */
330    public int hashCode()
331    {
332        int h = 37;
333
334        h += h * 17 + operation.getValue();
335        h += h * 17 + attribute.hashCode();
336
337        return h;
338    }
339
340
341    /**
342     * @see java.io.Externalizable#readExternal(ObjectInput)
343     */
344    public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
345    {
346        // The operation
347        operation = ModificationOperation.getOperation( in.readInt() );
348
349        // The EntryAttribute if we have some
350        boolean hasAttribute = in.readBoolean();
351
352        if ( hasAttribute )
353        {
354            attribute = new DefaultAttribute();
355            attribute.readExternal( in );
356        }
357    }
358
359
360    /**
361     * @see java.io.Externalizable#writeExternal(ObjectOutput)
362     */
363    public void writeExternal( ObjectOutput out ) throws IOException
364    {
365        // The operation
366        out.writeInt( operation.getValue() );
367
368        // The EntryAttribute if not null
369        if ( attribute != null )
370        {
371            out.writeBoolean( true );
372            attribute.writeExternal( out );
373        }
374        else
375        {
376            out.writeBoolean( false );
377        }
378
379        out.flush();
380    }
381
382
383    /**
384     * {@inheritDoc}
385     */
386    public DefaultModification clone()
387    {
388        try
389        {
390            DefaultModification clone = ( DefaultModification ) super.clone();
391
392            clone.attribute = this.attribute.clone();
393            return clone;
394        }
395        catch ( CloneNotSupportedException cnse )
396        {
397            return null;
398        }
399    }
400
401
402    /**
403     * @see Object#toString()
404     */
405    public String toString()
406    {
407        StringBuilder sb = new StringBuilder();
408
409        sb.append( "Modification: " ).
410            append( operation ).
411            append( "\n" ).
412            append( ", attribute : " ).
413            append( attribute );
414
415        return sb.toString();
416    }
417}