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.codec.factory;
021
022import java.util.Iterator;
023
024import org.apache.directory.api.asn1.ber.tlv.BerValue;
025import org.apache.directory.api.asn1.util.Asn1Buffer;
026import org.apache.directory.api.ldap.codec.api.LdapApiService;
027import org.apache.directory.api.ldap.codec.api.LdapCodecConstants;
028import org.apache.directory.api.ldap.model.entry.Attribute;
029import org.apache.directory.api.ldap.model.entry.Entry;
030import org.apache.directory.api.ldap.model.entry.Value;
031import org.apache.directory.api.ldap.model.message.AddRequest;
032import org.apache.directory.api.ldap.model.message.Message;
033import org.apache.directory.api.util.CollectionUtils;
034import org.apache.directory.api.util.Strings;
035
036/**
037 * The AddRequest factory.
038 *
039 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
040 */
041public final class AddRequestFactory implements Messagefactory
042{
043    /** The static instance */
044    public static final AddRequestFactory INSTANCE = new AddRequestFactory();
045
046    private AddRequestFactory()
047    {
048        // Nothing to do
049    }
050
051
052    /**
053     * Encode an entry's Attribute's values. It's done in reverse order, to have the
054     * last value encoded first in the reverse buffer.
055     * <br>
056     * The values are encoded this way :
057     * <pre>
058     * 0x31 LL attributeValues
059     *   0x04 LL attributeValue
060     *   ...
061     *   0x04 LL attributeValue
062     * </pre>
063     *
064     * @param buffer The buffer where to put the PDU
065     * @param iterator The iterator built on top of the values
066     */
067    private void encodeValueReverse( Asn1Buffer buffer, Iterator<Value> iterator )
068    {
069        iterator = CollectionUtils.reverse( iterator );
070        while ( iterator.hasNext() )
071        {
072            Value value = iterator.next();
073
074            // Encode the value
075            BerValue.encodeOctetString( buffer, value.getBytes() );
076        }
077    }
078
079
080    /**
081     * Encode the attributes, starting from the end. We iterate through the list
082     * of attributes in reverse order. The last attribute will be encoded first, when
083     * the end of the list will be reached, which is what we went, as we encode from
084     * the end.
085     * <br>
086     * An attribute is encoded this way:
087     * <pre>
088     *     0x30 LL attribute
089     *       0x04 LL attributeType
090     *       0x31 LL attributeValues
091     *         0x04 LL attributeValue
092     *         ...
093     *         0x04 LL attributeValue
094     * </pre>
095     *
096     * @param buffer The buffer where to put the PDU
097     * @param iterator The iterator built on top of the attributes
098     */
099    private void encodeAttributeReverse( Asn1Buffer buffer, Iterator<Attribute> iterator )
100    {
101        iterator = CollectionUtils.reverse( iterator );
102        while ( iterator.hasNext() )
103        {
104            Attribute attribute = iterator.next();
105
106            // Remind the current position
107            int start = buffer.getPos();
108
109            // The attributes values
110            if ( attribute.size() == 0 )
111            {
112                BerValue.encodeOctetString( buffer, Strings.EMPTY_BYTES );
113            }
114            else
115            {
116                encodeValueReverse( buffer, attribute.iterator() );
117            }
118
119            // Then the values' SET
120            BerValue.encodeSet( buffer, start );
121
122            // The attribute type
123            BerValue.encodeOctetString( buffer, attribute.getUpId() );
124
125            // The attribute sequence
126            BerValue.encodeSequence( buffer, start );
127        }
128    }
129
130    /**
131     * Encode the AddRequest message to a PDU.
132     * <br>
133     * AddRequest :
134     * <pre>
135     * 0x68 LL
136     *   0x04 LL entry
137     *   0x30 LL attributesList
138     *     0x30 LL attribute
139     *       0x04 LL attributeDescription
140     *       0x31 LL attributeValues
141     *         0x04 LL attributeValue
142     *         ...
143     *         0x04 LL attributeValue
144     *     ...
145     *     0x30 LL attribute
146     *       0x04 LL attributeDescription
147     *       0x31 LL attributeValue
148     *         0x04 LL attributeValue
149     *         ...
150     *         0x04 LL attributeValue
151     * </pre>
152     *
153     * @param codec The LdapApiService instance
154     * @param buffer The buffer where to put the PDU
155     * @param message the AbandonRequest to encode
156     */
157    @Override
158    public void encodeReverse( LdapApiService codec, Asn1Buffer buffer, Message message )
159    {
160        int start = buffer.getPos();
161        AddRequest addRequest = ( AddRequest ) message;
162
163        // The partial attribute list
164        Entry entry = addRequest.getEntry();
165
166        if ( entry.size() != 0 )
167        {
168            // Encode the attributes
169            encodeAttributeReverse( buffer, entry.iterator() );
170        }
171
172        // The attributes sequence
173        BerValue.encodeSequence( buffer, start );
174
175        // The entry DN
176        BerValue.encodeOctetString( buffer, entry.getDn().getName() );
177
178        // The AddRequest Tag
179        BerValue.encodeSequence( buffer, LdapCodecConstants.ADD_REQUEST_TAG, start );
180    }
181}