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 2006-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS 026 */ 027package org.opends.server.replication.protocol; 028 029import java.util.zip.DataFormatException; 030 031import org.opends.server.controls.SubtreeDeleteControl; 032import org.opends.server.core.DeleteOperation; 033import org.opends.server.core.DeleteOperationBasis; 034import org.opends.server.protocols.internal.InternalClientConnection; 035import org.opends.server.replication.common.CSN; 036import org.opends.server.types.DN; 037import org.opends.server.types.operation.PostOperationDeleteOperation; 038 039import static org.opends.server.replication.protocol.OperationContext.*; 040 041/** 042 * Object used when sending delete information to replication servers. 043 */ 044public class DeleteMsg extends LDAPUpdateMsg 045{ 046 private String initiatorsName; 047 048 /** Whether the DEL operation is a subtree DEL. */ 049 private boolean isSubtreeDelete; 050 051 /** 052 * Creates a new delete message. 053 * 054 * @param operation the Operation from which the message must be created. 055 */ 056 DeleteMsg(PostOperationDeleteOperation operation) 057 { 058 super((OperationContext) operation.getAttachment(SYNCHROCONTEXT), 059 operation.getEntryDN()); 060 try 061 { 062 isSubtreeDelete = 063 operation.getRequestControl(SubtreeDeleteControl.DECODER) != null; 064 } 065 catch(Exception e) 066 {/* do nothing */} 067 } 068 069 /** 070 * Creates a new delete message. 071 * 072 * @param dn The dn with which the message must be created. 073 * @param csn The CSN with which the message must be created. 074 * @param entryUUID The unique id with which the message must be created. 075 */ 076 public DeleteMsg(DN dn, CSN csn, String entryUUID) 077 { 078 super(new DeleteContext(csn, entryUUID), dn); 079 } 080 081 /** 082 * Creates a new Add message from a byte[]. 083 * 084 * @param in The byte[] from which the operation must be read. 085 * @throws DataFormatException The input byte[] is not a valid DeleteMsg 086 */ 087 DeleteMsg(byte[] in) throws DataFormatException 088 { 089 final ByteArrayScanner scanner = new ByteArrayScanner(in); 090 decodeHeader(scanner, MSG_TYPE_DELETE, MSG_TYPE_DELETE_V1); 091 092 if (protocolVersion >= 4) 093 { 094 decodeBody_V4(scanner); 095 } 096 else 097 { 098 // Keep the previous protocol version behavior - when we don't know the 099 // truth, we assume 'subtree' 100 isSubtreeDelete = true; 101 } 102 } 103 104 /** {@inheritDoc} */ 105 @Override 106 public DeleteOperation createOperation(InternalClientConnection connection, 107 DN newDN) 108 { 109 DeleteOperation del = new DeleteOperationBasis(connection, 110 InternalClientConnection.nextOperationID(), 111 InternalClientConnection.nextMessageID(), null, newDN); 112 113 if (isSubtreeDelete) 114 { 115 del.addRequestControl(new SubtreeDeleteControl(false)); 116 } 117 118 DeleteContext ctx = new DeleteContext(getCSN(), getEntryUUID()); 119 del.setAttachment(SYNCHROCONTEXT, ctx); 120 return del; 121 } 122 123 // ============ 124 // Msg encoding 125 // ============ 126 127 /** {@inheritDoc} */ 128 @Override 129 public byte[] getBytes_V1() 130 { 131 return encodeHeader_V1(MSG_TYPE_DELETE_V1) 132 .toByteArray(); 133 } 134 135 /** {@inheritDoc} */ 136 @Override 137 public byte[] getBytes_V23() 138 { 139 return encodeHeader(MSG_TYPE_DELETE,ProtocolVersion.REPLICATION_PROTOCOL_V3) 140 .toByteArray(); 141 } 142 143 /** {@inheritDoc} */ 144 @Override 145 public byte[] getBytes_V45(short protocolVersion) 146 { 147 final ByteArrayBuilder builder = 148 encodeHeader(MSG_TYPE_DELETE, protocolVersion); 149 builder.appendString(initiatorsName); 150 builder.appendIntUTF8(encodedEclIncludes.length); 151 builder.appendZeroTerminatedByteArray(encodedEclIncludes); 152 builder.appendBoolean(isSubtreeDelete); 153 return builder.toByteArray(); 154 } 155 156 // ============ 157 // Msg decoding 158 // ============ 159 160 private void decodeBody_V4(ByteArrayScanner scanner) 161 throws DataFormatException 162 { 163 initiatorsName = scanner.nextString(); 164 165 final int eclAttrLen = scanner.nextIntUTF8(); 166 encodedEclIncludes = scanner.nextByteArray(eclAttrLen); 167 scanner.skipZeroSeparator(); 168 169 isSubtreeDelete = scanner.nextBoolean(); 170 } 171 172 /** {@inheritDoc} */ 173 @Override 174 public String toString() 175 { 176 if (protocolVersion >= ProtocolVersion.REPLICATION_PROTOCOL_V1) 177 { 178 return "DeleteMsg content: " + 179 " protocolVersion: " + protocolVersion + 180 " dn: " + dn + 181 " csn: " + csn + 182 " uniqueId: " + entryUUID + 183 " assuredFlag: " + assuredFlag + 184 (protocolVersion >= ProtocolVersion.REPLICATION_PROTOCOL_V2 ? 185 " assuredMode: " + assuredMode + 186 " safeDataLevel: " + safeDataLevel 187 : ""); 188 } 189 return "!!! Unknown version: " + protocolVersion + "!!!"; 190 } 191 192 /** {@inheritDoc} */ 193 @Override 194 public int size() 195 { 196 return encodedEclIncludes.length + headerSize(); 197 } 198 199 /** 200 * Set the initiator's name of this change. 201 * 202 * @param iname the initiator's name. 203 */ 204 public void setInitiatorsName(String iname) 205 { 206 initiatorsName = iname; 207 } 208 209 /** 210 * Get the initiator's name of this change. 211 * @return the initiator's name. 212 */ 213 public String getInitiatorsName() 214 { 215 return initiatorsName; 216 } 217 218 /** 219 * Set the subtree flag. 220 * @param subtreeDelete the subtree flag. 221 */ 222 public void setSubtreeDelete(boolean subtreeDelete) 223 { 224 this.isSubtreeDelete = subtreeDelete; 225 } 226 227 /** 228 * Get the subtree flag. 229 * @return the subtree flag. 230 */ 231 public boolean isSubtreeDelete() 232 { 233 return this.isSubtreeDelete; 234 } 235}