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}