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 22:52:31 +0200 (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 }