001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 package org.apache.directory.shared.ldap.codec.search.controls.persistentSearch; 021 022 023 import java.nio.ByteBuffer; 024 025 import org.apache.directory.shared.asn1.ber.tlv.TLV; 026 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag; 027 import org.apache.directory.shared.asn1.ber.tlv.Value; 028 import org.apache.directory.shared.asn1.codec.EncoderException; 029 import org.apache.directory.shared.i18n.I18n; 030 import org.apache.directory.shared.ldap.codec.controls.AbstractControl; 031 import org.apache.directory.shared.ldap.codec.search.controls.ChangeType; 032 033 034 /** 035 * A persistence search object 036 * 037 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 038 * @version $Rev: 912399 $, $Date: 2010-02-21 21:52:31 +0100 (Sun, 21 Feb 2010) $, 039 */ 040 public class PersistentSearchControl extends AbstractControl 041 { 042 /** This control OID */ 043 public static final String CONTROL_OID = "2.16.840.1.113730.3.4.3"; 044 045 /** 046 * If changesOnly is TRUE, the server MUST NOT return any existing entries 047 * that match the search criteria. Entries are only returned when they are 048 * changed (added, modified, deleted, or subject to a modifyDN operation). 049 */ 050 private boolean changesOnly = true; 051 052 /** 053 * If returnECs is TRUE, the server MUST return an Entry Change Notification 054 * control with each entry returned as the result of changes. 055 */ 056 private boolean returnECs = false; 057 058 /** 059 * As changes are made to the server, the effected entries MUST be returned 060 * to the client if they match the standard search criteria and if the 061 * operation that caused the change is included in the changeTypes field. 062 * The changeTypes field is the logical OR of one or more of these values: 063 * add (1), 064 * delete (2), 065 * modify (4), 066 * modDN (8). 067 */ 068 private int changeTypes = CHANGE_TYPES_MAX; 069 070 /** Definition of the change types */ 071 public static final int CHANGE_TYPE_ADD = 1; 072 public static final int CHANGE_TYPE_DELETE = 2; 073 public static final int CHANGE_TYPE_MODIFY = 4; 074 public static final int CHANGE_TYPE_MODDN = 8; 075 076 /** Min and Max values for the possible combined change types */ 077 public static final int CHANGE_TYPES_MIN = CHANGE_TYPE_ADD; 078 public static final int CHANGE_TYPES_MAX = CHANGE_TYPE_ADD | CHANGE_TYPE_DELETE | CHANGE_TYPE_MODIFY | CHANGE_TYPE_MODDN; 079 080 /** A temporary storage for a psearch length */ 081 private int psearchSeqLength; 082 083 /** 084 * Default constructor 085 * 086 */ 087 public PersistentSearchControl() 088 { 089 super( CONTROL_OID ); 090 091 decoder = new PersistentSearchControlDecoder(); 092 } 093 094 public void setChangesOnly( boolean changesOnly ) 095 { 096 this.changesOnly = changesOnly; 097 } 098 099 100 public boolean isChangesOnly() 101 { 102 return changesOnly; 103 } 104 105 106 public void setReturnECs( boolean returnECs ) 107 { 108 this.returnECs = returnECs; 109 } 110 111 112 public boolean isReturnECs() 113 { 114 return returnECs; 115 } 116 117 118 public void setChangeTypes( int changeTypes ) 119 { 120 this.changeTypes = changeTypes; 121 } 122 123 124 public int getChangeTypes() 125 { 126 return changeTypes; 127 } 128 129 /** 130 * Compute the PagedSearchControl length, which is the sum 131 * of the control length and the value length. 132 * 133 * <pre> 134 * PersistentSearchControl value length : 135 * 136 * 0x30 L1 137 * | 138 * +--> 0x02 0x0(1-4) [0..2^31-1] (changeTypes) 139 * +--> 0x01 0x01 [0x00 | 0xFF] (changeOnly) 140 * +--> 0x01 0x01 [0x00 | 0xFF] (returnRCs) 141 * </pre> 142 */ 143 public int computeLength() 144 { 145 int changeTypesLength = 1 + 1 + Value.getNbBytes( changeTypes ); 146 int changesOnlyLength = 1 + 1 + 1; 147 int returnRCsLength = 1 + 1 + 1; 148 149 psearchSeqLength = changeTypesLength + changesOnlyLength + returnRCsLength; 150 int valueLength = 1 + TLV.getNbBytes( psearchSeqLength ) + psearchSeqLength; 151 152 // Call the super class to compute the global control length 153 return super.computeLength( valueLength ); 154 } 155 156 157 /** 158 * Encodes the persistent search control. 159 * 160 * @param buffer The encoded sink 161 * @return A ByteBuffer that contains the encoded PDU 162 * @throws EncoderException If anything goes wrong. 163 */ 164 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 165 { 166 if ( buffer == null ) 167 { 168 throw new EncoderException( I18n.err( I18n.ERR_04023 ) ); 169 } 170 171 // Encode the Control envelop 172 super.encode( buffer ); 173 174 // Encode the OCTET_STRING tag 175 buffer.put( UniversalTag.OCTET_STRING_TAG ); 176 buffer.put( TLV.getBytes( valueLength ) ); 177 178 // Now encode the PagedSearch specific part 179 buffer.put( UniversalTag.SEQUENCE_TAG ); 180 buffer.put( TLV.getBytes( psearchSeqLength ) ); 181 182 Value.encode( buffer, changeTypes ); 183 Value.encode( buffer, changesOnly ); 184 Value.encode( buffer, returnECs ); 185 186 return buffer; 187 } 188 189 190 /** 191 * {@inheritDoc} 192 */ 193 public byte[] getValue() 194 { 195 if ( value == null ) 196 { 197 try 198 { 199 computeLength(); 200 ByteBuffer buffer = ByteBuffer.allocate( valueLength ); 201 202 // Now encode the PagedSearch specific part 203 buffer.put( UniversalTag.SEQUENCE_TAG ); 204 buffer.put( TLV.getBytes( psearchSeqLength ) ); 205 206 Value.encode( buffer, changeTypes ); 207 Value.encode( buffer, changesOnly ); 208 Value.encode( buffer, returnECs ); 209 210 value = buffer.array(); 211 } 212 catch ( Exception e ) 213 { 214 return null; 215 } 216 } 217 218 return value; 219 } 220 221 222 public boolean isNotificationEnabled( ChangeType changeType ) 223 { 224 return ( changeType.getValue() & changeTypes ) > 0; 225 } 226 227 228 public void enableNotification( ChangeType changeType ) 229 { 230 changeTypes |= changeType.getValue(); 231 } 232 233 234 /** 235 * Return a String representing this PSearchControl. 236 */ 237 public String toString() 238 { 239 StringBuffer sb = new StringBuffer(); 240 241 sb.append( " Persistant Search Control\n" ); 242 sb.append( " oid : " ).append( getOid() ).append( '\n' ); 243 sb.append( " critical : " ).append( isCritical() ).append( '\n' ); 244 sb.append( " changeTypes : '" ).append( changeTypes ).append( "'\n" ); 245 sb.append( " changesOnly : '" ).append( changesOnly ).append( "'\n" ); 246 sb.append( " returnECs : '" ).append( returnECs ).append( "'\n" ); 247 248 return sb.toString(); 249 } 250 }