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