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