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