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