/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2009-2010 Sun Microsystems, Inc. * Portions Copyright 2013 ForgeRock AS. */ package org.opends.server.replication.protocol; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.zip.DataFormatException; import org.opends.server.replication.common.ChangeNumber; import org.opends.server.util.StaticUtils; /** * This class specifies the parameters of a search request on the ECL. * It is used as an interface between the requestor (plugin part) * - either as an han */ public class StartECLSessionMsg extends ReplicationMsg { /** * This specifies that the ECL is requested from a provided cookie value * defined as a MultiDomainServerState. */ public final static short REQUEST_TYPE_FROM_COOKIE = 0; /** * This specifies that the ECL is requested from a provided interval * of change numbers (as defined by draft-good-ldap-changelog [CHANGELOG] * and NOT replication change numbers). * TODO: not yet implemented */ public final static short REQUEST_TYPE_FROM_DRAFT_CHANGE_NUMBER = 1; /** * This specifies that the ECL is requested only for the entry that have * a repl change number matching the provided one. * TODO: not yet implemented */ public final static short REQUEST_TYPE_EQUALS_REPL_CHANGE_NUMBER = 2; /** * This specifies that the request on the ECL is a PERSISTENT search * with changesOnly = false. */ public final static short PERSISTENT = 0; /** * This specifies that the request on the ECL is a NOT a PERSISTENT search. */ public final static short NON_PERSISTENT = 1; /** * This specifies that the request on the ECL is a PERSISTENT search * with changesOnly = true. */ public final static short PERSISTENT_CHANGES_ONLY = 2; /** The type of request as defined by REQUEST_TYPE_... */ private short eclRequestType; /** * When eclRequestType = FROM_COOKIE, specifies the provided cookie value. */ private String crossDomainServerState = ""; /** * When eclRequestType = FROM_CHANGE_NUMBER, specifies the provided change * number first and last - [CHANGELOG]. */ private int firstDraftChangeNumber = -1; private int lastDraftChangeNumber = -1; /** * When eclRequestType = EQUALS_REPL_CHANGE_NUMBER, specifies the provided * replication change number. */ private ChangeNumber changeNumber; /** Specifies whether the search is persistent and changesOnly. */ private short isPersistent = NON_PERSISTENT; /** * A string helping debugging and tracing the client operation related when * processing, on the RS side, a request on the ECL. */ private String operationId = ""; /** Excluded domains. */ private Set excludedBaseDNs = new HashSet(); /** * Creates a new StartSessionMsg message from its encoded form. * * @param in The byte array containing the encoded form of the message. * @throws java.util.zip.DataFormatException If the byte array does not * contain a valid encoded form of the message. */ public StartECLSessionMsg(byte[] in) throws DataFormatException { /* * The message is stored in the form: * * * (each referral url terminates with 0) */ try { /* first bytes are the header */ int pos = 0; /* first byte is the type */ if (in.length < 1 || in[pos++] != MSG_TYPE_START_ECL_SESSION) { throw new DataFormatException( "Input is not a valid " + this.getClass().getCanonicalName()); } // start mode int length = getNextLength(in, pos); eclRequestType = Short.valueOf(new String(in, pos, length, "UTF-8")); pos += length +1; // sequenceNumber length = getNextLength(in, pos); firstDraftChangeNumber = Integer.valueOf(new String(in, pos, length, "UTF-8")); pos += length +1; // stopSequenceNumber length = getNextLength(in, pos); lastDraftChangeNumber = Integer.valueOf(new String(in, pos, length, "UTF-8")); pos += length +1; // replication changeNumber length = getNextLength(in, pos); String changenumberStr = new String(in, pos, length, "UTF-8"); pos += length + 1; changeNumber = new ChangeNumber(changenumberStr); // persistentSearch mode length = getNextLength(in, pos); isPersistent = Short.valueOf(new String(in, pos, length, "UTF-8")); pos += length + 1; // generalized state length = getNextLength(in, pos); crossDomainServerState = new String(in, pos, length, "UTF-8"); pos += length + 1; // operation id length = getNextLength(in, pos); operationId = new String(in, pos, length, "UTF-8"); pos += length + 1; // excluded DN length = getNextLength(in, pos); String excludedDNsString = new String(in, pos, length, "UTF-8"); if (excludedDNsString.length()>0) { String[] excludedDNsStr = excludedDNsString.split(";"); Collections.addAll(this.excludedBaseDNs, excludedDNsStr); } pos += length + 1; } catch (UnsupportedEncodingException e) { throw new DataFormatException("UTF-8 is not supported by this jvm."); } catch (IllegalArgumentException e) { throw new DataFormatException(e.getMessage()); } } /** * Creates a new StartSessionMsg message with the given required parameters. */ public StartECLSessionMsg() { eclRequestType = REQUEST_TYPE_FROM_COOKIE; crossDomainServerState = ""; firstDraftChangeNumber = -1; lastDraftChangeNumber = -1; changeNumber = new ChangeNumber(0,0,0); isPersistent = NON_PERSISTENT; operationId = "-1"; excludedBaseDNs = new HashSet(); } /** * {@inheritDoc} */ @Override public byte[] getBytes(short protocolVersion) { String excludedBaseDNsString = StaticUtils.collectionToString(excludedBaseDNs, ";"); try { byte[] byteMode = Short.toString(eclRequestType).getBytes("UTF-8"); byte[] byteSequenceNumber = String.valueOf(firstDraftChangeNumber).getBytes("UTF-8"); byte[] byteStopSequenceNumber = String.valueOf(lastDraftChangeNumber).getBytes("UTF-8"); byte[] byteChangeNumber = changeNumber.toString().getBytes("UTF-8"); byte[] bytePsearch = Short.toString(isPersistent).getBytes(); byte[] byteGeneralizedState = String.valueOf(crossDomainServerState).getBytes("UTF-8"); byte[] byteOperationId = String.valueOf(operationId).getBytes("UTF-8"); byte[] byteExcludedDNs = String.valueOf(excludedBaseDNsString).getBytes("UTF-8"); int length = byteMode.length + 1 + byteSequenceNumber.length + 1 + byteStopSequenceNumber.length + 1 + byteChangeNumber.length + 1 + bytePsearch.length + 1 + byteGeneralizedState.length + 1 + byteOperationId.length + 1 + byteExcludedDNs.length + 1 + 1; byte[] resultByteArray = new byte[length]; int pos = 0; resultByteArray[pos++] = MSG_TYPE_START_ECL_SESSION; pos = addByteArray(byteMode, resultByteArray, pos); pos = addByteArray(byteSequenceNumber, resultByteArray, pos); pos = addByteArray(byteStopSequenceNumber, resultByteArray, pos); pos = addByteArray(byteChangeNumber, resultByteArray, pos); pos = addByteArray(bytePsearch, resultByteArray, pos); pos = addByteArray(byteGeneralizedState, resultByteArray, pos); pos = addByteArray(byteOperationId, resultByteArray, pos); pos = addByteArray(byteExcludedDNs, resultByteArray, pos); return resultByteArray; } catch (IOException e) { // never happens return null; } } /** * {@inheritDoc} */ @Override public String toString() { return getClass().getCanonicalName() + " [" + " requestType="+ eclRequestType + " persistentSearch=" + isPersistent + " changeNumber=" + changeNumber + " firstDraftChangeNumber=" + firstDraftChangeNumber + " lastDraftChangeNumber=" + lastDraftChangeNumber + " generalizedState=" + crossDomainServerState + " operationId=" + operationId + " excludedDNs=" + excludedBaseDNs + "]"; } /** * Getter on the changer number start. * @return the changer number start. */ public int getFirstDraftChangeNumber() { return firstDraftChangeNumber; } /** * Getter on the changer number stop. * @return the change number stop. */ public int getLastDraftChangeNumber() { return lastDraftChangeNumber; } /** * Setter on the first changer number (as defined by [CHANGELOG]). * @param firstDraftChangeNumber the provided first change number. */ public void setFirstDraftChangeNumber(int firstDraftChangeNumber) { this.firstDraftChangeNumber = firstDraftChangeNumber; } /** * Setter on the last changer number (as defined by [CHANGELOG]). * @param lastDraftChangeNumber the provided last change number. */ public void setLastDraftChangeNumber(int lastDraftChangeNumber) { this.lastDraftChangeNumber = lastDraftChangeNumber; } /** * Getter on the replication change number. * @return the replication change number. */ public ChangeNumber getChangeNumber() { return changeNumber; } /** * Setter on the replication change number. * @param changeNumber the provided replication change number. */ public void setChangeNumber(ChangeNumber changeNumber) { this.changeNumber = changeNumber; } /** * Getter on the type of request. * @return the type of request. */ public short getECLRequestType() { return eclRequestType; } /** * Setter on the type of request. * @param eclRequestType the provided type of request. */ public void setECLRequestType(short eclRequestType) { this.eclRequestType = eclRequestType; } /** * Getter on the persistent property of the search request on the ECL. * @return the persistent property. */ public short isPersistent() { return this.isPersistent; } /** * Setter on the persistent property of the search request on the ECL. * @param isPersistent the provided persistent property. */ public void setPersistent(short isPersistent) { this.isPersistent = isPersistent; } /** * Getter of the cross domain server state. * @return the cross domain server state. */ public String getCrossDomainServerState() { return this.crossDomainServerState; } /** * Setter of the cross domain server state. * @param crossDomainServerState the provided cross domain server state. */ public void setCrossDomainServerState(String crossDomainServerState) { this.crossDomainServerState = crossDomainServerState; } /** * Setter of the operation id. * @param operationId The provided operation id. */ public void setOperationId(String operationId) { this.operationId = operationId; } /** * Getter on the operation id. * @return the operation id. */ public String getOperationId() { return this.operationId; } /** * Getter on the list of excluded baseDNs. * * @return the list of excluded baseDNs. */ public Set getExcludedBaseDNs() { return this.excludedBaseDNs; } /** * Setter on the list of excluded baseDNs. * * @param excludedBaseDNs * the provided list of excluded baseDNs. */ public void setExcludedDNs(Set excludedBaseDNs) { this.excludedBaseDNs = excludedBaseDNs; } }