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}