/*
|
* 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<String> excludedServiceIDs = new HashSet<String>();
|
|
/**
|
* 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:
|
* <message type><status><assured flag><assured mode><safe data level>
|
* <list of referrals urls>
|
* (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.excludedServiceIDs, 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";
|
excludedServiceIDs = new HashSet<String>();
|
}
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public byte[] getBytes(short protocolVersion)
|
{
|
String excludedSIDsString =
|
StaticUtils.collectionToString(excludedServiceIDs, ";");
|
|
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(excludedSIDsString).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=" + excludedServiceIDs + "]";
|
}
|
|
/**
|
* 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 opration 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 ServiceIDs.
|
* @return the list of excluded ServiceIDs.
|
*/
|
public Set<String> getExcludedServiceIDs()
|
{
|
return this.excludedServiceIDs;
|
}
|
|
/**
|
* Setter on the list of excluded ServiceIDs.
|
* @param excludedServiceIDs the provided list of excluded ServiceIDs.
|
*/
|
public void setExcludedDNs(Set<String> excludedServiceIDs)
|
{
|
this.excludedServiceIDs = excludedServiceIDs;
|
}
|
|
}
|