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 }