1 /* 2 * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.naming.ldap; 27 28 import java.io.IOException; 29 import com.sun.jndi.ldap.Ber; 30 import com.sun.jndi.ldap.BerEncoder; 31 32 /** 33 * Requests that the results of a search operation be returned by the LDAP 34 * server in batches of a specified size. 35 * The requestor controls the rate at which batches are returned by the rate 36 * at which it invokes search operations. 37 * <p> 38 * The following code sample shows how the class may be used: 39 * <pre>{@code 40 * 41 * // Open an LDAP association 42 * LdapContext ctx = new InitialLdapContext(); 43 * 44 * // Activate paged results 45 * int pageSize = 20; // 20 entries per page 46 * byte[] cookie = null; 47 * int total; 48 * ctx.setRequestControls(new Control[]{ 49 * new PagedResultsControl(pageSize, Control.CRITICAL) }); 50 * 51 * do { 52 * // Perform the search 53 * NamingEnumeration results = 54 * ctx.search("", "(objectclass=*)", new SearchControls()); 55 * 56 * // Iterate over a batch of search results 57 * while (results != null && results.hasMore()) { 58 * // Display an entry 59 * SearchResult entry = (SearchResult)results.next(); 60 * System.out.println(entry.getName()); 61 * System.out.println(entry.getAttributes()); 62 * 63 * // Handle the entry's response controls (if any) 64 * if (entry instanceof HasControls) { 65 * // ((HasControls)entry).getControls(); 66 * } 67 * } 68 * // Examine the paged results control response 69 * Control[] controls = ctx.getResponseControls(); 70 * if (controls != null) { 71 * for (int i = 0; i < controls.length; i++) { 72 * if (controls[i] instanceof PagedResultsResponseControl) { 73 * PagedResultsResponseControl prrc = 74 * (PagedResultsResponseControl)controls[i]; 75 * total = prrc.getResultSize(); 76 * cookie = prrc.getCookie(); 77 * } else { 78 * // Handle other response controls (if any) 79 * } 80 * } 81 * } 82 * 83 * // Re-activate paged results 84 * ctx.setRequestControls(new Control[]{ 85 * new PagedResultsControl(pageSize, cookie, Control.CRITICAL) }); 86 * } while (cookie != null); 87 * 88 * // Close the LDAP association 89 * ctx.close(); 90 * ... 91 * 92 * } </pre> 93 * <p> 94 * This class implements the LDAPv3 Control for paged-results as defined in 95 * <a href="http://www.ietf.org/rfc/rfc2696.txt">RFC 2696</a>. 96 * 97 * The control's value has the following ASN.1 definition: 98 * <pre>{@code 99 * 100 * realSearchControlValue ::= SEQUENCE { 101 * size INTEGER (0..maxInt), 102 * -- requested page size from client 103 * -- result set size estimate from server 104 * cookie OCTET STRING 105 * } 106 * 107 * }</pre> 108 * 109 * @since 1.5 110 * @see PagedResultsResponseControl 111 * @author Vincent Ryan 112 */ 113 final public class PagedResultsControl extends BasicControl { 114 115 /** 116 * The paged-results control's assigned object identifier 117 * is 1.2.840.113556.1.4.319. 118 */ 119 public static final String OID = "1.2.840.113556.1.4.319"; 120 121 private static final byte[] EMPTY_COOKIE = new byte[0]; 122 123 private static final long serialVersionUID = 6684806685736844298L; 124 125 /** 126 * Constructs a control to set the number of entries to be returned per 127 * page of results. 128 * 129 * @param pageSize The number of entries to return in a page. 130 * @param criticality If true then the server must honor the control 131 * and return search results as indicated by 132 * pageSize or refuse to perform the search. 133 * If false, then the server need not honor the 134 * control. 135 * @exception IOException If an error was encountered while encoding the 136 * supplied arguments into a control. 137 */ 138 public PagedResultsControl(int pageSize, boolean criticality) 139 throws IOException { 140 141 super(OID, criticality, null); 142 value = setEncodedValue(pageSize, EMPTY_COOKIE); 143 } 144 145 /** 146 * Constructs a control to set the number of entries to be returned per 147 * page of results. The cookie is provided by the server and may be 148 * obtained from the paged-results response control. 149 * <p> 150 * A sequence of paged-results can be abandoned by setting the pageSize 151 * to zero and setting the cookie to the last cookie received from the 152 * server. 153 * 154 * @param pageSize The number of entries to return in a page. 155 * @param cookie A possibly null server-generated cookie. 156 * @param criticality If true then the server must honor the control 157 * and return search results as indicated by 158 * pageSize or refuse to perform the search. 159 * If false, then the server need not honor the 160 * control. 161 * @exception IOException If an error was encountered while encoding the 162 * supplied arguments into a control. 163 */ 164 public PagedResultsControl(int pageSize, byte[] cookie, 165 boolean criticality) throws IOException { 166 167 super(OID, criticality, null); 168 if (cookie == null) { 169 cookie = EMPTY_COOKIE; 170 } 171 value = setEncodedValue(pageSize, cookie); 172 } 173 174 /* 175 * Encodes the paged-results control's value using ASN.1 BER. 176 * The result includes the BER tag and length for the control's value but 177 * does not include the control's object identifier and criticality setting. 178 * 179 * @param pageSize The number of entries to return in a page. 180 * @param cookie A non-null server-generated cookie. 181 * @return A possibly null byte array representing the ASN.1 BER encoded 182 * value of the LDAP paged-results control. 183 * @exception IOException If a BER encoding error occurs. 184 */ 185 private byte[] setEncodedValue(int pageSize, byte[] cookie) 186 throws IOException { 187 188 // build the ASN.1 encoding 189 BerEncoder ber = new BerEncoder(10 + cookie.length); 190 191 ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR); 192 ber.encodeInt(pageSize); 193 ber.encodeOctetString(cookie, Ber.ASN_OCTET_STR); 194 ber.endSeq(); 195 196 return ber.getTrimmedBuf(); 197 } 198 }