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
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.replication.protocol;
028
029 import static org.opends.server.replication.protocol.OperationContext.*;
030
031 import java.io.UnsupportedEncodingException;
032 import java.util.zip.DataFormatException;
033
034 import org.opends.server.core.ModifyDNOperationBasis;
035 import org.opends.server.protocols.asn1.ASN1OctetString;
036 import org.opends.server.protocols.internal.InternalClientConnection;
037 import org.opends.server.replication.common.ChangeNumber;
038 import org.opends.server.types.AbstractOperation;
039 import org.opends.server.types.DN;
040 import org.opends.server.types.DirectoryException;
041 import org.opends.server.types.RDN;
042 import org.opends.server.types.operation.PostOperationModifyDNOperation;
043
044 /**
045 * Message used to send Modify DN information.
046 */
047 public class ModifyDNMsg extends UpdateMessage
048 {
049 private String newRDN;
050 private String newSuperior;
051 private boolean deleteOldRdn;
052 private String newSuperiorId;
053 private static final long serialVersionUID = -4905520652801395185L;
054
055 /**
056 * construct a new Modify DN message.
057 *
058 * @param operation The operation to use for building the message
059 */
060 public ModifyDNMsg(PostOperationModifyDNOperation operation)
061 {
062 super((OperationContext) operation.getAttachment(SYNCHROCONTEXT),
063 operation.getRawEntryDN().stringValue());
064
065 ModifyDnContext ctx =
066 (ModifyDnContext) operation.getAttachment(SYNCHROCONTEXT);
067 newSuperiorId = ctx.getNewParentId();
068
069 deleteOldRdn = operation.deleteOldRDN();
070 if (operation.getRawNewSuperior() != null)
071 newSuperior = operation.getRawNewSuperior().stringValue();
072 else
073 newSuperior = null;
074 newRDN = operation.getRawNewRDN().stringValue();
075 }
076
077 /**
078 * construct a new Modify DN message.
079 *
080 * @param dn The dn to use for building the message.
081 * @param changeNumber The changeNumberto use for building the message.
082 * @param uid The unique id to use for building the message.
083 * @param newParentUid The new parent unique id to use for building
084 * the message.
085 * @param deleteOldRdn boolean indicating if old rdn must be deleted to use
086 * for building the message.
087 * @param newSuperior The new Superior entry to use for building the message.
088 * @param newRDN The new Rdn to use for building the message.
089 */
090 public ModifyDNMsg(String dn, ChangeNumber changeNumber, String uid,
091 String newParentUid, boolean deleteOldRdn,
092 String newSuperior, String newRDN)
093 {
094 super(new ModifyDnContext(changeNumber, uid, newParentUid), dn);
095
096 newSuperiorId = newParentUid;
097
098 this.deleteOldRdn = deleteOldRdn;
099 this.newSuperior = newSuperior;
100 this.newRDN = newRDN;
101 }
102
103 /**
104 * Creates a new ModifyDN message from a byte[].
105 *
106 * @param in The byte[] from which the operation must be read.
107 * @throws DataFormatException The input byte[] is not a valid AddMsg.
108 * @throws UnsupportedEncodingException If UTF8 is not supported.
109 */
110 public ModifyDNMsg(byte[] in) throws DataFormatException,
111 UnsupportedEncodingException
112 {
113 super(in);
114
115 int pos = decodeHeader(MSG_TYPE_MODIFYDN_REQUEST, in);
116
117 /* read the newRDN
118 * first calculate the length then construct the string
119 */
120 int length = getNextLength(in, pos);
121 newRDN = new String(in, pos, length, "UTF-8");
122 pos += length + 1;
123
124 /* read the newSuperior
125 * first calculate the length then construct the string
126 */
127 length = getNextLength(in, pos);
128 if (length != 0)
129 newSuperior = new String(in, pos, length, "UTF-8");
130 else
131 newSuperior = null;
132 pos += length + 1;
133
134 /* read the new parent Id
135 */
136 length = getNextLength(in, pos);
137 if (length != 0)
138 newSuperiorId = new String(in, pos, length, "UTF-8");
139 else
140 newSuperiorId = null;
141 pos += length + 1;
142
143 /* get the deleteoldrdn flag */
144 if (in[pos] == 0)
145 deleteOldRdn = false;
146 else
147 deleteOldRdn = true;
148 }
149
150 /**
151 * {@inheritDoc}
152 */
153 @Override
154 public AbstractOperation createOperation(
155 InternalClientConnection connection, String newDn)
156 {
157 ModifyDNOperationBasis moddn = new ModifyDNOperationBasis(connection,
158 InternalClientConnection.nextOperationID(),
159 InternalClientConnection.nextMessageID(), null,
160 new ASN1OctetString(newDn), new ASN1OctetString(newRDN),
161 deleteOldRdn,
162 (newSuperior == null ? null : new ASN1OctetString(newSuperior)));
163 ModifyDnContext ctx = new ModifyDnContext(getChangeNumber(), getUniqueId(),
164 newSuperiorId);
165 moddn.setAttachment(SYNCHROCONTEXT, ctx);
166 return moddn;
167 }
168
169 /**
170 * Get the byte array representation of this Message.
171 *
172 * @return The byte array representation of this Message.
173 *
174 * @throws UnsupportedEncodingException When the encoding of the message
175 * failed because the UTF-8 encoding is not supported.
176 */
177 @Override
178 public byte[] getBytes() throws UnsupportedEncodingException
179 {
180 byte[] byteNewRdn = newRDN.getBytes("UTF-8");
181 byte[] byteNewSuperior = null;
182 byte[] byteNewSuperiorId = null;
183
184 // calculate the length necessary to encode the parameters
185 int length = byteNewRdn.length + 1 + 1;
186 if (newSuperior != null)
187 {
188 byteNewSuperior = newSuperior.getBytes("UTF-8");
189 length += byteNewSuperior.length + 1;
190 }
191 else
192 length += 1;
193
194 if (newSuperiorId != null)
195 {
196 byteNewSuperiorId = newSuperiorId.getBytes("UTF-8");
197 length += byteNewSuperiorId.length + 1;
198 }
199 else
200 length += 1;
201
202 byte[] resultByteArray = encodeHeader(MSG_TYPE_MODIFYDN_REQUEST, length);
203 int pos = resultByteArray.length - length;
204
205 /* put the new RDN and a terminating 0 */
206 pos = addByteArray(byteNewRdn, resultByteArray, pos);
207
208 /* put the newsuperior and a terminating 0 */
209 if (newSuperior != null)
210 {
211 pos = addByteArray(byteNewSuperior, resultByteArray, pos);
212 }
213 else
214 resultByteArray[pos++] = 0;
215
216 /* put the newsuperiorId and a terminating 0 */
217 if (newSuperiorId != null)
218 {
219 pos = addByteArray(byteNewSuperiorId, resultByteArray, pos);
220 }
221 else
222 resultByteArray[pos++] = 0;
223
224 /* put the deleteoldrdn flag */
225 if (deleteOldRdn)
226 resultByteArray[pos++] = 1;
227 else
228 resultByteArray[pos++] = 0;
229
230 return resultByteArray;
231 }
232
233 /**
234 * {@inheritDoc}
235 */
236 @Override
237 public String toString()
238 {
239 return ("MODDN " + getDn() + " " + newRDN + " " + newSuperior + " " +
240 getChangeNumber());
241 }
242
243 /**
244 * Set the new superior.
245 * @param string the new superior.
246 */
247 public void setNewSuperior(String string)
248 {
249 newSuperior = string;
250 }
251
252 /**
253 * Get the new RDN of this operation.
254 *
255 * @return The new RDN of this operation.
256 */
257 public String getNewRDN()
258 {
259 return newRDN;
260 }
261
262 /**
263 * Set the new RDN of this operation.
264 * @param newRDN the new RDN of this operation.
265 */
266 public void setNewRDN(String newRDN)
267 {
268 this.newRDN = newRDN;
269 }
270
271 /**
272 * Check if this MSG will change the DN of the target entry to be
273 * the same as the dn given as a parameter.
274 * @param targetDn the DN to use when checking if this MSG will change
275 * the DN of the entry to a given DN.
276 * @return A boolean indicating if the modify DN MSG will change the DN of
277 * the target entry to be the same as the dn given as a parameter.
278 */
279 public boolean newDNIsParent(DN targetDn)
280 {
281 try
282 {
283 DN newDN;
284 if (newSuperior == null)
285 {
286 DN parentDn = DN.decode(this.getDn()).getParent();
287 newDN = parentDn.concat(RDN.decode(newRDN));
288 }
289 else
290 {
291 String newStringDN = newRDN + "," + newSuperior;
292 newDN = DN.decode(newStringDN);
293 }
294
295
296 if (newDN.isAncestorOf(targetDn))
297 return true;
298 else
299 return false;
300 } catch (DirectoryException e)
301 {
302 // The DN was not a correct DN, and therefore does not a parent of the
303 // DN given as a parameter.
304 return false;
305 }
306 }
307
308 /**
309 * Check if the new dn of this ModifyDNMsg is the same as the targetDN
310 * given in parameter.
311 *
312 * @param targetDN The targetDN to use to check for equality.
313 *
314 * @return A boolean indicating if the targetDN if the same as the new DN of
315 * the ModifyDNMsg.
316 */
317 public boolean newDNIsEqual(DN targetDN)
318 {
319 try
320 {
321 String newStringDN = newRDN + "," + newSuperior;
322 DN newDN = DN.decode(newStringDN);
323
324 if (newDN.equals(targetDN))
325 return true;
326 else
327 return false;
328 } catch (DirectoryException e)
329 {
330 // The DN was not a correct DN, and therefore does not match the
331 // DN given as a parameter.
332 return false;
333 }
334 }
335
336 /**
337 * Check if the new parent of the modifyDNMsg is the same as the targetDN
338 * given in parameter.
339 *
340 * @param targetDN the targetDN to use when checking equality.
341 *
342 * @return A boolean indicating if the new parent of the modifyDNMsg is the
343 * same as the targetDN.
344 */
345 public boolean newParentIsEqual(DN targetDN)
346 {
347 try
348 {
349 DN newSuperiorDN = DN.decode(newSuperior);
350
351 if (newSuperiorDN.equals(targetDN))
352 return true;
353 else
354 return false;
355 } catch (DirectoryException e)
356 {
357 // The newsuperior was not a correct DN, and therefore does not match the
358 // DN given as a parameter.
359 return false;
360 }
361 }
362
363 }