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.codec.factory;
021
022import java.util.Collection;
023import java.util.Iterator;
024
025import org.apache.directory.api.asn1.ber.tlv.BerValue;
026import org.apache.directory.api.asn1.util.Asn1Buffer;
027import org.apache.directory.api.ldap.codec.api.LdapApiService;
028import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
029import org.apache.directory.api.ldap.model.entry.Attribute;
030import org.apache.directory.api.ldap.model.entry.Modification;
031import org.apache.directory.api.ldap.model.entry.ModificationOperation;
032import org.apache.directory.api.ldap.model.entry.Value;
033import org.apache.directory.api.ldap.model.message.Message;
034import org.apache.directory.api.ldap.model.message.ModifyRequest;
035
036/**
037 * The ModifyRequest factory.
038 *
039 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
040 */
041public final class ModifyRequestFactory implements Messagefactory
042{
043    /** The static instance */
044    public static final ModifyRequestFactory INSTANCE = new ModifyRequestFactory();
045
046    private ModifyRequestFactory()
047    {
048        // Nothing to do
049    }
050
051
052    /**
053     * Encode the values, recursively
054     * <pre>
055     * 0x04 LL attributeValue
056     * ...
057     * 0x04 LL attributeValue
058     * </pre>
059     *
060     * @param buffer The buffer where to put the PDU
061     * @param values the values to encode
062     */
063    private void encodeValues( Asn1Buffer buffer, Iterator<Value> values )
064    {
065        if ( values.hasNext() )
066        {
067            Value value = values.next();
068
069            // Recurse on the values
070            encodeValues( buffer, values );
071
072            // The value
073            if ( value.isHumanReadable() )
074            {
075                BerValue.encodeOctetString( buffer, value.getString() );
076            }
077            else
078            {
079                BerValue.encodeOctetString( buffer, value.getBytes() );
080            }
081        }
082    }
083
084    /**
085     * Recursively encode the modifications, starting from the last one.
086     * <pre>
087     * 0x30 LL modification sequence
088     *   0x0A 0x01 operation
089     *   0x30 LL modification
090     *     0x04 LL type
091     *     0x31 LL vals
092     *       0x04 LL attributeValue
093     *       ...
094     *       0x04 LL attributeValue
095     * </pre>
096     *
097     * @param buffer The buffer where to put the PDU
098     * @param modifications the modifications to encode
099     */
100    private void encodeModifications( Asn1Buffer buffer, Iterator<Modification> modifications )
101    {
102        if ( modifications.hasNext() )
103        {
104            Modification modification = modifications.next();
105
106            // Recurse
107            encodeModifications( buffer, modifications );
108
109            int start = buffer.getPos();
110
111            // The Attribute
112            Attribute attribute = modification.getAttribute();
113
114            // The values, if any
115            if ( modification.getAttribute().size() != 0 )
116            {
117                encodeValues( buffer, modification.getAttribute().iterator() );
118
119                // the value set
120                BerValue.encodeSet( buffer, start );
121            }
122            else if ( modification.getOperation() != ModificationOperation.INCREMENT_ATTRIBUTE )
123            {
124                // the value set, if not a INCREMENT operation
125                BerValue.encodeSet( buffer, start );
126            }
127
128            // The attribute type
129            BerValue.encodeOctetString( buffer, attribute.getUpId() );
130
131            // The attribute sequence
132            BerValue.encodeSequence( buffer, start );
133
134            // The operation
135            BerValue.encodeEnumerated( buffer, modification.getOperation().getValue() );
136
137            // The modification sequence
138            BerValue.encodeSequence( buffer, start );
139        }
140    }
141
142    /**
143     * Encode the ModifyRequest message to a PDU.
144     * <br>
145     * ModifyRequest :
146     * <pre>
147     * 0x66 LL
148     *   0x04 LL object
149     *   0x30 LL modifications
150     *     0x30 LL modification sequence
151     *       0x0A 0x01 operation
152     *       0x30 LL modification
153     *         0x04 LL type
154     *         0x31 LL vals
155     *           0x04 LL attributeValue
156     *           ...
157     *           0x04 LL attributeValue
158     *     ...
159     *     0x30 LL modification sequence
160     *       0x0A 0x01 operation
161     *       0x30 LL modification
162     *         0x04 LL type
163     *         0x31 LL vals
164     *           0x04 LL attributeValue
165     *           ...
166     *           0x04 LL attributeValue
167     * </pre>
168     *
169     * @param codec The LdapApiService instance
170     * @param buffer The buffer where to put the PDU
171     * @param message the ModifyRequest to encode
172     */
173    @Override
174    public void encodeReverse( LdapApiService codec, Asn1Buffer buffer, Message message )
175    {
176        int start = buffer.getPos();
177        ModifyRequest modifyRequest = ( ModifyRequest ) message;
178
179        // The modifications, if any
180        Collection<Modification> modifications = modifyRequest.getModifications();
181
182        if ( ( modifications != null ) && ( !modifications.isEmpty() ) )
183        {
184            encodeModifications( buffer, modifications.iterator() );
185
186            // The modifications sequence
187            BerValue.encodeSequence( buffer, start );
188        }
189
190        // The entry DN
191        BerValue.encodeOctetString( buffer, modifyRequest.getName().getName() );
192
193        // The ModifyRequest tag
194        BerValue.encodeSequence( buffer, LdapCodecConstants.MODIFY_REQUEST_TAG, start );
195    }
196}