001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2009-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2013-2015 ForgeRock AS
026 */
027package org.opends.server.replication.protocol;
028
029import java.io.IOException;
030import java.util.ArrayList;
031import java.util.List;
032
033import org.forgerock.opendj.io.ASN1;
034import org.forgerock.opendj.io.ASN1Reader;
035import org.forgerock.opendj.io.ASN1Writer;
036import org.forgerock.opendj.ldap.ByteStringBuilder;
037import org.forgerock.opendj.ldap.schema.AttributeUsage;
038import org.opends.server.protocols.ldap.LDAPAttribute;
039import org.opends.server.protocols.ldap.LDAPModification;
040import org.opends.server.replication.common.CSN;
041import org.opends.server.replication.plugin.EntryHistorical;
042import org.opends.server.types.*;
043
044/**
045 * This class holds every common code for the modify messages (mod, moddn).
046 */
047public abstract class ModifyCommonMsg extends LDAPUpdateMsg {
048
049  /**
050   * The modifications kept encoded in the message.
051   */
052  protected byte[] encodedMods = new byte[0];
053
054  /**
055   * Creates a new ModifyCommonMsg.
056   */
057  public ModifyCommonMsg()
058  {
059    super();
060  }
061
062  /**
063   * Creates a new ModifyCommonMsg with the given informations.
064   *
065   * @param ctx The replication Context of the operation for which the
066   *            update message must be created,.
067   * @param dn The DN of the entry on which the change
068   *           that caused the creation of this object happened
069   */
070  public ModifyCommonMsg(OperationContext ctx, DN dn)
071  {
072   super(ctx, dn);
073  }
074
075  /**
076   * Creates a new ModifyCommonMsg with the given informations.
077   *
078   * @param csn       The CSN of the operation for which the
079   *                  UpdateMessage is created.
080   * @param entryUUID The Unique identifier of the entry that is updated
081   *                  by the operation for which the UpdateMessage is created.
082   * @param dn        The DN of the entry on which the change
083   *                  that caused the creation of this object happened
084   */
085  public ModifyCommonMsg(CSN csn, String entryUUID, DN dn)
086  {
087    super(csn, entryUUID, dn);
088  }
089
090  /**
091   * Set the Modification associated to the UpdateMsg to the provided value.
092   *
093   * @param mods The new Modification associated to this ModifyMsg.
094   */
095  public void setMods(List<Modification> mods)
096  {
097    encodedMods = encodeMods(mods);
098  }
099
100  /**
101   * Get the Modifications associated to the UpdateMsg to the provided value.
102   * @throws LDAPException In case of LDAP decoding exception
103   * @throws IOException In case of ASN1 decoding exception
104   * @return the list of modifications
105   */
106  public List<Modification> getMods() throws IOException, LDAPException
107  {
108    return decodeMods(encodedMods);
109  }
110
111  // ============
112  // Msg encoding
113  // ============
114
115  /**
116   * Encode an ArrayList of Modification into a byte[] suitable
117   * for storage in a database or send on the network.
118   *
119   * @param mods the ArrayList of Modification to be encoded.
120   * @return The encoded modifications.
121   */
122  protected byte[] encodeMods(List<Modification> mods)
123  {
124    if (mods == null || mods.isEmpty())
125    {
126      return new byte[0];
127    }
128
129    ByteStringBuilder byteBuilder = new ByteStringBuilder();
130    ASN1Writer writer = ASN1.getWriter(byteBuilder);
131
132    for (Modification mod : mods)
133    {
134      Attribute attr = mod.getAttribute();
135      AttributeType type = attr.getAttributeType();
136      if (type != null
137          && AttributeUsage.DSA_OPERATION.equals(type.getUsage()) )
138      {
139        // Attributes with a dsaOperation usage should not be synchronized.
140        // skip them.
141        continue;
142      }
143
144      if (!EntryHistorical.isHistoricalAttribute(attr))
145      {
146        LDAPModification ldapmod = new LDAPModification(
147          mod.getModificationType(), new LDAPAttribute(mod.getAttribute()));
148        try
149        {
150          ldapmod.write(writer);
151        }
152        catch(Exception e)
153        {
154          // DO SOMETHING
155        }
156      }
157    }
158    return byteBuilder.toByteArray();
159  }
160
161  // ============
162  // Msg decoding
163  // ============
164
165  /**
166   * Decode mods from the provided byte array.
167   * @param in The provided byte array.
168   * @throws IOException when occurs.
169   * @throws LDAPException when occurs.
170   * @return The decoded mods.
171   */
172  protected List<Modification> decodeMods(byte[] in) throws IOException,
173      LDAPException
174  {
175    List<Modification> mods = new ArrayList<>();
176    ASN1Reader reader = ASN1.getReader(in);
177    while (reader.hasNextElement())
178    {
179      mods.add(LDAPModification.decode(reader).toModification());
180    }
181    return mods;
182  }
183
184  /**
185   * Decode raw mods from the provided byte array.
186   * @param in The provided byte array.
187   * @return The decoded mods.
188   * @throws IOException when occurs.
189   * @throws LDAPException when occurs.
190   */
191  protected List<RawModification> decodeRawMods(byte[] in)
192      throws LDAPException, IOException
193  {
194    List<RawModification> ldapmods = new ArrayList<>();
195    ASN1Reader asn1Reader = ASN1.getReader(in);
196    while(asn1Reader.hasNextElement())
197    {
198      ldapmods.add(LDAPModification.decode(asn1Reader));
199    }
200    return ldapmods;
201  }
202}