001 /* 002 * Copyright 2011-2015 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005 /* 006 * Copyright (C) 2015 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021 package com.unboundid.ldap.sdk.unboundidds.extensions; 022 023 024 025 import java.util.ArrayList; 026 027 import com.unboundid.asn1.ASN1Boolean; 028 import com.unboundid.asn1.ASN1Element; 029 import com.unboundid.asn1.ASN1OctetString; 030 import com.unboundid.asn1.ASN1Sequence; 031 import com.unboundid.ldap.sdk.Control; 032 import com.unboundid.ldap.sdk.ExtendedRequest; 033 import com.unboundid.ldap.sdk.LDAPException; 034 import com.unboundid.ldap.sdk.ResultCode; 035 import com.unboundid.util.Debug; 036 import com.unboundid.util.NotMutable; 037 import com.unboundid.util.StaticUtils; 038 import com.unboundid.util.ThreadSafety; 039 import com.unboundid.util.ThreadSafetyLevel; 040 041 import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*; 042 043 044 045 /** 046 * <BLOCKQUOTE> 047 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID 048 * LDAP SDK for Java. It is not available for use in applications that 049 * include only the Standard Edition of the LDAP SDK, and is not supported for 050 * use in conjunction with non-UnboundID products. 051 * </BLOCKQUOTE> 052 * This class provides an implementation of the start administrative session 053 * extended request, which clients may use to indicate that they are going to 054 * perform a set of administrative operations in the server. It may be used 055 * to identify the client to the server and to indicate whether subsequent 056 * requests received on the connection should be processed using worker threads 057 * in a dedicated thread pool (subject to server configuration restrictions). 058 * <BR><BR> 059 * This extended request has an OID of 1.3.6.1.4.1.30221.2.6.13, and it must 060 * have a value with the following encoding: 061 * <PRE> 062 * StartAdminSessionValue ::= SEQUENCE { 063 * clientName [0] OCTET STRING OPTIONAL, 064 * useDedicatedThreadPool [1] BOOLEAN DEFAULT FALSE, 065 * ... } 066 * </PRE> 067 * <BR><BR> 068 * <H2>Example</H2> 069 * The following example demonstrates the process for creating an administrative 070 * session and using that session to request monitor information using a 071 * dedicated worker thread. 072 * <PRE> 073 * // Establish a connection to the server. 074 * LDAPConnection connection = new LDAPConnection(host, port); 075 * 076 * // Use the start administrative session operation to begin an administrative 077 * // session and request that operations in the session use the dedicated 078 * // thread pool. 079 * ExtendedResult extendedResult = connection.processExtendedOperation( 080 * new StartAdministrativeSessionExtendedRequest("Test Client", true)); 081 * 082 * // Authenticate the connection. It is strongly recommended that the 083 * // administrative session be created before the connection is authenticated. 084 * // Attempting to authenticate the connection before creating the 085 * // administrative session may result in the bind using a "regular" worker 086 * // thread rather than an administrative session worker thread, and if all 087 * // normal worker threads are busy or stuck, then the bind request may be 088 * // blocked. 089 * BindResult bindResult = connection.bind(userDN, password); 090 * 091 * // Use the connection to perform operations that may benefit from using an 092 * // administrative session (e.g., operations that troubleshoot and attempt to 093 * // correct some problem with the server). In this example, we'll just 094 * // request all monitor entries from the server. 095 * List<MonitorEntry> monitorEntries = 096 * MonitorManager.getMonitorEntries(connection); 097 * 098 * // Use the end administrative session operation to end the administrative 099 * // session and resume using normal worker threads for subsequent operations. 100 * // This isn't strictly needed if we just want to close the connection. 101 * extendedResult = connection.processExtendedOperation( 102 * new EndAdministrativeSessionExtendedRequest()); 103 * 104 * // Do other operations that don't need an administrative session. 105 * 106 * connection.close(); 107 * </PRE> 108 * 109 * @see EndAdministrativeSessionExtendedRequest 110 */ 111 @NotMutable() 112 @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 113 public final class StartAdministrativeSessionExtendedRequest 114 extends ExtendedRequest 115 { 116 /** 117 * The OID (1.3.6.1.4.1.30221.2.6.13) for the start administrative session 118 * extended request. 119 */ 120 public static final String START_ADMIN_SESSION_REQUEST_OID = 121 "1.3.6.1.4.1.30221.2.6.13"; 122 123 124 125 /** 126 * The BER type for the client name element of the extended request value. 127 */ 128 private static final byte TYPE_CLIENT_NAME = (byte) 0x80; 129 130 131 132 /** 133 * The BER type for the use dedicated thread pool element of the extended 134 * request value. 135 */ 136 private static final byte TYPE_USE_DEDICATED_THREAD_POOL = (byte) 0x81; 137 138 139 140 /** 141 * The serial version UID for this serializable class. 142 */ 143 private static final long serialVersionUID = -2684374559100906505L; 144 145 146 147 // Indicates whether the client has requested that the server use a dedicated 148 // thread pool for processing operations during the administrative session. 149 private final boolean useDedicatedThreadPool; 150 151 // The name of the client application issuing this request. 152 private final String clientName; 153 154 155 156 /** 157 * Creates a new start administrative session extended request with the 158 * provided information. 159 * 160 * @param clientName The name of the client application issuing 161 * this request. It may be {@code null} if no 162 * client name should be provided. 163 * @param useDedicatedThreadPool Indicates whether the server should use a 164 * dedicated worker thread pool for requests 165 * processed by this client. Note that the 166 * server may define restrictions around the 167 * use of a dedicated thread pool. 168 * @param controls The set of controls to include in the 169 * request. 170 */ 171 public StartAdministrativeSessionExtendedRequest(final String clientName, 172 final boolean useDedicatedThreadPool, final Control... controls) 173 { 174 super(START_ADMIN_SESSION_REQUEST_OID, 175 encodeValue(clientName, useDedicatedThreadPool), 176 controls); 177 178 this.clientName = clientName; 179 this.useDedicatedThreadPool = useDedicatedThreadPool; 180 } 181 182 183 184 /** 185 * Creates a new start administrative session extended request from the 186 * provided generic extended request. 187 * 188 * @param extendedRequest The generic extended request to use to create this 189 * start administrative session extended request. 190 * 191 * @throws LDAPException If a problem occurs while decoding the request. 192 */ 193 public StartAdministrativeSessionExtendedRequest( 194 final ExtendedRequest extendedRequest) 195 throws LDAPException 196 { 197 super(extendedRequest); 198 199 final ASN1OctetString value = extendedRequest.getValue(); 200 if (value == null) 201 { 202 throw new LDAPException(ResultCode.DECODING_ERROR, 203 ERR_START_ADMIN_SESSION_REQUEST_NO_VALUE.get()); 204 } 205 206 207 String appName = null; 208 boolean dedicatedPool = false; 209 210 try 211 { 212 final ASN1Sequence valueSequence = 213 ASN1Sequence.decodeAsSequence(value.getValue()); 214 for (final ASN1Element e : valueSequence.elements()) 215 { 216 switch (e.getType()) 217 { 218 case TYPE_CLIENT_NAME: 219 appName = ASN1OctetString.decodeAsOctetString(e).stringValue(); 220 break; 221 case TYPE_USE_DEDICATED_THREAD_POOL: 222 dedicatedPool = ASN1Boolean.decodeAsBoolean(e).booleanValue(); 223 break; 224 default: 225 throw new LDAPException(ResultCode.DECODING_ERROR, 226 ERR_START_ADMIN_SESSION_REQUEST_UNKNOWN_VALUE_ELEMENT_TYPE.get( 227 StaticUtils.toHex(e.getType()))); 228 } 229 } 230 } 231 catch (final LDAPException le) 232 { 233 Debug.debugException(le); 234 throw le; 235 } 236 catch (final Exception e) 237 { 238 Debug.debugException(e); 239 throw new LDAPException(ResultCode.DECODING_ERROR, 240 ERR_START_ADMIN_SESSION_REQUEST_ERROR_DECODING_VALUE.get( 241 StaticUtils.getExceptionMessage(e)), 242 e); 243 } 244 245 clientName = appName; 246 useDedicatedThreadPool = dedicatedPool; 247 } 248 249 250 251 /** 252 * Encodes the provided information into an ASN.1 octet string suitable for 253 * use as the value of this extended request. 254 * 255 * @param clientName The name of the client application issuing 256 * this request. It may be {@code null} if no 257 * client name should be provided. 258 * @param useDedicatedThreadPool Indicates whether the server should use a 259 * dedicated worker thread pool for requests 260 * processed by this client. Note that the 261 * server may define restrictions around the 262 * use of a dedicated thread pool. 263 * 264 * @return The ASN.1 octet string containing the encoded value. 265 */ 266 private static ASN1OctetString encodeValue(final String clientName, 267 final boolean useDedicatedThreadPool) 268 { 269 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2); 270 271 if (clientName != null) 272 { 273 elements.add(new ASN1OctetString(TYPE_CLIENT_NAME, clientName)); 274 } 275 276 if (useDedicatedThreadPool) 277 { 278 elements.add(new ASN1Boolean(TYPE_USE_DEDICATED_THREAD_POOL, true)); 279 } 280 281 return new ASN1OctetString(new ASN1Sequence(elements).encode()); 282 } 283 284 285 286 /** 287 * Retrieves the name of the client application issuing this request, if 288 * available. 289 * 290 * @return The name of the client application issuing this request, or 291 * {@code null} if it was not included in the request. 292 */ 293 public String getClientName() 294 { 295 return clientName; 296 } 297 298 299 300 /** 301 * Indicates whether the server should attempt to use a dedicated worker 302 * thread pool for requests from this client. 303 * 304 * @return {@code true} if the server should attempt to use a dedicated 305 * worker thread pool for requests from this client, or {@code false} 306 * if not. 307 */ 308 public boolean useDedicatedThreadPool() 309 { 310 return useDedicatedThreadPool; 311 } 312 313 314 315 /** 316 * {@inheritDoc} 317 */ 318 @Override() 319 public StartAdministrativeSessionExtendedRequest duplicate() 320 { 321 return duplicate(getControls()); 322 } 323 324 325 326 /** 327 * {@inheritDoc} 328 */ 329 @Override() 330 public StartAdministrativeSessionExtendedRequest duplicate( 331 final Control[] controls) 332 { 333 return new StartAdministrativeSessionExtendedRequest(clientName, 334 useDedicatedThreadPool, controls); 335 } 336 337 338 339 /** 340 * {@inheritDoc} 341 */ 342 @Override() 343 public String getExtendedRequestName() 344 { 345 return INFO_EXTENDED_REQUEST_NAME_START_ADMIN_SESSION.get(); 346 } 347 348 349 350 /** 351 * {@inheritDoc} 352 */ 353 @Override() 354 public void toString(final StringBuilder buffer) 355 { 356 buffer.append("StartAdministrativeSessionExtendedRequest("); 357 358 if (clientName != null) 359 { 360 buffer.append("clientName='"); 361 buffer.append(clientName); 362 buffer.append("', "); 363 } 364 365 buffer.append("useDedicatedThreadPool="); 366 buffer.append(useDedicatedThreadPool); 367 368 final Control[] controls = getControls(); 369 if (controls.length > 0) 370 { 371 buffer.append(", controls={"); 372 for (int i=0; i < controls.length; i++) 373 { 374 if (i > 0) 375 { 376 buffer.append(", "); 377 } 378 379 buffer.append(controls[i]); 380 } 381 buffer.append('}'); 382 } 383 384 buffer.append(')'); 385 } 386 }