001 /*
002 * Copyright 2013-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 import java.util.Collection;
027 import java.util.Collections;
028 import java.util.Iterator;
029 import java.util.List;
030 import java.util.TreeSet;
031
032 import com.unboundid.asn1.ASN1Element;
033 import com.unboundid.asn1.ASN1OctetString;
034 import com.unboundid.asn1.ASN1Sequence;
035 import com.unboundid.ldap.sdk.Control;
036 import com.unboundid.ldap.sdk.ExtendedResult;
037 import com.unboundid.ldap.sdk.LDAPException;
038 import com.unboundid.ldap.sdk.ResultCode;
039 import com.unboundid.util.Debug;
040 import com.unboundid.util.StaticUtils;
041 import com.unboundid.util.ThreadSafety;
042 import com.unboundid.util.ThreadSafetyLevel;
043 import com.unboundid.util.Validator;
044
045 import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
046
047
048
049 /**
050 * <BLOCKQUOTE>
051 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID
052 * LDAP SDK for Java. It is not available for use in applications that
053 * include only the Standard Edition of the LDAP SDK, and is not supported for
054 * use in conjunction with non-UnboundID products.
055 * </BLOCKQUOTE>
056 * This class provides an implementation of an extended result that can be used
057 * to retrieve a list of all available versions of the configuration within a
058 * server. This may include not only the currently-active configuration, but
059 * also former configurations that have been archived, and the baseline
060 * configuration for the current server version.
061 * <BR><BR>
062 * The OID for this extended result is 1.3.6.1.4.1.30221.2.6.27. If the request
063 * was processed successfully, then the response will have a value with the
064 * following encoding:
065 * <PRE>
066 * ListConfigurationsResult ::= SEQUENCE {
067 * activeConfigFileName [0] OCTET STRING,
068 * baselineConfigFileNames [1] OCTET STRING OPTIONAL,
069 * archivedConfigFileNames [2] SEQUENCE OF OCTET STRING OPTIONAL,
070 * ... }
071 * </PRE>
072 */
073 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
074 public final class ListConfigurationsExtendedResult
075 extends ExtendedResult
076 {
077 /**
078 * The OID (1.3.6.1.4.1.30221.2.6.27) for the list configurations extended
079 * result.
080 */
081 public static final String LIST_CONFIGS_RESULT_OID =
082 "1.3.6.1.4.1.30221.2.6.27";
083
084
085
086 /**
087 * The BER type for the element holding the filename used for the active
088 * configuration.
089 */
090 private static final byte TYPE_ACTIVE_CONFIG_FILE_NAME = (byte) 0x80;
091
092
093
094 /**
095 * The BER type for the element holding the filename used for the baseline
096 * configuration.
097 */
098 private static final byte TYPE_BASELINE_CONFIG_FILE_NAMES = (byte) 0xA1;
099
100
101
102 /**
103 * The BER type for the element holding the filenames used for the archived
104 * configurations.
105 */
106 private static final byte TYPE_ARCHIVED_CONFIG_FILE_NAMES = (byte) 0xA2;
107
108
109
110 /**
111 * The serial version UID for this serializable class.
112 */
113 private static final long serialVersionUID = -466738484294922561L;
114
115
116
117 // The names of the archived configuration files.
118 private final List<String> archivedFileNames;
119
120 // The name of the baseline configuration file.
121 private final List<String> baselineFileNames;
122
123 // The name of the active configuration file.
124 private final String activeFileName;
125
126
127
128 /**
129 * Creates a new list configurations extended result from the provided generic
130 * extended result.
131 *
132 * @param result The generic extended result to be decoded as a list
133 * configurations extended result.
134 *
135 * @throws LDAPException If the provided extended result cannot be parsed as
136 * a valid list configurations extended result.
137 */
138 public ListConfigurationsExtendedResult(final ExtendedResult result)
139 throws LDAPException
140 {
141 super(result);
142
143 final ASN1OctetString value = result.getValue();
144 if (value == null)
145 {
146 activeFileName = null;
147 baselineFileNames = Collections.emptyList();
148 archivedFileNames = Collections.emptyList();
149 return;
150 }
151
152 try
153 {
154 String activeName = null;
155 List<String> archivedNames = Collections.emptyList();
156 List<String> baselineNames = null;
157 final ASN1Element[] elements =
158 ASN1Sequence.decodeAsSequence(value.getValue()).elements();
159 for (final ASN1Element e : elements)
160 {
161 switch (e.getType())
162 {
163 case TYPE_ACTIVE_CONFIG_FILE_NAME:
164 activeName = ASN1OctetString.decodeAsOctetString(e).stringValue();
165 break;
166 case TYPE_BASELINE_CONFIG_FILE_NAMES:
167 final ASN1Element[] baselineNameElements =
168 ASN1Sequence.decodeAsSequence(e).elements();
169 baselineNames = new ArrayList<String>(baselineNameElements.length);
170 for (final ASN1Element el : baselineNameElements)
171 {
172 baselineNames.add(
173 ASN1OctetString.decodeAsOctetString(el).stringValue());
174 }
175 archivedNames = Collections.unmodifiableList(baselineNames);
176 break;
177 case TYPE_ARCHIVED_CONFIG_FILE_NAMES:
178 final ASN1Element[] archivedNameElements =
179 ASN1Sequence.decodeAsSequence(e).elements();
180 archivedNames = new ArrayList<String>(archivedNameElements.length);
181 for (final ASN1Element el : archivedNameElements)
182 {
183 archivedNames.add(
184 ASN1OctetString.decodeAsOctetString(el).stringValue());
185 }
186 archivedNames = Collections.unmodifiableList(archivedNames);
187 break;
188 default:
189 throw new LDAPException(ResultCode.DECODING_ERROR,
190 ERR_LIST_CONFIGS_RESULT_UNEXPECTED_ELEMENT_TYPE.get(
191 StaticUtils.toHex(e.getType())));
192 }
193 }
194
195 activeFileName = activeName;
196 archivedFileNames = archivedNames;
197 baselineFileNames = baselineNames;
198
199 if (activeFileName == null)
200 {
201 throw new LDAPException(ResultCode.DECODING_ERROR,
202 ERR_LIST_CONFIGS_RESULT_NO_ACTIVE_CONFIG.get());
203 }
204 }
205 catch (final LDAPException le)
206 {
207 Debug.debugException(le);
208 throw le;
209 }
210 catch (final Exception e)
211 {
212 Debug.debugException(e);
213 throw new LDAPException(ResultCode.DECODING_ERROR,
214 ERR_LIST_CONFIGS_RESULT_ERROR_PARSING_VALUE.get(
215 StaticUtils.getExceptionMessage(e)),
216 e);
217 }
218 }
219
220
221
222 /**
223 * Creates a new list configurations extended result with the provided
224 * information.
225 *
226 * @param messageID The message ID for the LDAP message that is
227 * associated with this LDAP result.
228 * @param resultCode The result code from the response.
229 * @param diagnosticMessage The diagnostic message from the response, if
230 * available.
231 * @param matchedDN The matched DN from the response, if available.
232 * @param referralURLs The set of referral URLs from the response, if
233 * available.
234 * @param activeFileName The name of the active configuration file, if
235 * available.
236 * @param baselineFileNames The names of the baseline configuration files
237 * for current and former server versions, if
238 * available. It must be {@code null} or empty if
239 * the active file name is {@code null}.
240 * @param archivedFileNames The names of the archived configuration files,
241 * if available. It must be {@code null} or empty
242 * if the active file name is {@code null}.
243 * @param responseControls The set of controls from the response, if
244 * available.
245 */
246 public ListConfigurationsExtendedResult(final int messageID,
247 final ResultCode resultCode, final String diagnosticMessage,
248 final String matchedDN, final String[] referralURLs,
249 final String activeFileName,
250 final Collection<String> baselineFileNames,
251 final Collection<String> archivedFileNames,
252 final Control... responseControls)
253 {
254 super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
255 ((activeFileName == null) ? null : LIST_CONFIGS_RESULT_OID),
256 encodeValue(activeFileName, baselineFileNames, archivedFileNames),
257 responseControls);
258
259 this.activeFileName = activeFileName;
260
261 if (baselineFileNames == null)
262 {
263 this.baselineFileNames = Collections.emptyList();
264 }
265 else
266 {
267 this.baselineFileNames = Collections.unmodifiableList(
268 new ArrayList<String>(baselineFileNames));
269 }
270
271 if (archivedFileNames == null)
272 {
273 this.archivedFileNames = Collections.emptyList();
274 }
275 else
276 {
277 this.archivedFileNames = Collections.unmodifiableList(
278 new ArrayList<String>(archivedFileNames));
279 }
280 }
281
282
283
284 /**
285 * Creates an ASN.1 octet string containing an encoded representation of the
286 * value for a list configurations extended result with the provided
287 * information.
288 *
289 * @param activeFileName The name of the active configuration file, if
290 * available.
291 * @param baselineFileNames The names of the baseline configuration files
292 * for current and former server versions, if
293 * available. It must be {@code null} or empty if
294 * the active file name is {@code null}.
295 * @param archivedFileNames The names of the archived configuration files,
296 * if available. It must be {@code null} or empty
297 * if the active file name is {@code null}.
298 *
299 * @return An ASN.1 octet string containing an encoded representation of the
300 * value for a list configurations extended result, or {@code null}
301 * if a result with the provided information should not have a value.
302 */
303 public static ASN1OctetString encodeValue(final String activeFileName,
304 final Collection<String> baselineFileNames,
305 final Collection<String> archivedFileNames)
306 {
307 if (activeFileName == null)
308 {
309 Validator.ensureTrue(
310 ((baselineFileNames == null) || baselineFileNames.isEmpty()),
311 "The baseline filename must be null if the active filename is null");
312 Validator.ensureTrue(
313 ((archivedFileNames == null) || archivedFileNames.isEmpty()),
314 "The archived filenames must be null or empty if the active " +
315 "filename is null");
316 return null;
317 }
318
319 final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3);
320 elements.add(
321 new ASN1OctetString(TYPE_ACTIVE_CONFIG_FILE_NAME, activeFileName));
322
323 if ((baselineFileNames != null) && (! baselineFileNames.isEmpty()))
324 {
325 final TreeSet<String> sortedBaselineNames =
326 new TreeSet<String>(baselineFileNames);
327 final ArrayList<ASN1Element> baselineNameElements =
328 new ArrayList<ASN1Element>(sortedBaselineNames.size());
329 for (final String s : sortedBaselineNames)
330 {
331 baselineNameElements.add(new ASN1OctetString(s));
332 }
333 elements.add(new ASN1Sequence(TYPE_BASELINE_CONFIG_FILE_NAMES,
334 baselineNameElements));
335 }
336
337 if ((archivedFileNames != null) && (! archivedFileNames.isEmpty()))
338 {
339 final TreeSet<String> sortedArchivedNames =
340 new TreeSet<String>(archivedFileNames);
341 final ArrayList<ASN1Element> archivedNameElements =
342 new ArrayList<ASN1Element>(sortedArchivedNames.size());
343 for (final String s : sortedArchivedNames)
344 {
345 archivedNameElements.add(new ASN1OctetString(s));
346 }
347 elements.add(new ASN1Sequence(TYPE_ARCHIVED_CONFIG_FILE_NAMES,
348 archivedNameElements));
349 }
350
351 return new ASN1OctetString(new ASN1Sequence(elements).encode());
352 }
353
354
355
356 /**
357 * Retrieves the name of the active configuration file the server is
358 * currently using, if available.
359 *
360 * @return The name of the active configuration file the server is
361 * currently using, or {@code null} this is not available.
362 */
363 public String getActiveFileName()
364 {
365 return activeFileName;
366 }
367
368
369
370 /**
371 * Retrieves a list containing the names of the baseline configuration files
372 * (i.e., the files containing the initial "out-of-the-box" configuration for
373 * various server versions), if available.
374 *
375 * @return A list containing the names of the baseline configuration files,
376 * or an empty list if this is not available.
377 */
378 public List<String> getBaselineFileNames()
379 {
380 return baselineFileNames;
381 }
382
383
384
385 /**
386 * Retrieves a list containing the names of the archived configuration files,
387 * if available.
388 *
389 * @return A list containing the names of the archived configuration files,
390 * or an empty list if this is not available.
391 */
392 public List<String> getArchivedFileNames()
393 {
394 return archivedFileNames;
395 }
396
397
398
399 /**
400 * {@inheritDoc}
401 */
402 @Override()
403 public String getExtendedResultName()
404 {
405 return INFO_EXTENDED_RESULT_NAME_LIST_CONFIGS.get();
406 }
407
408
409
410 /**
411 * {@inheritDoc}
412 */
413 @Override()
414 public void toString(final StringBuilder buffer)
415 {
416 buffer.append("ListConfigurationsExtendedResult(resultCode=");
417 buffer.append(getResultCode());
418
419 final int messageID = getMessageID();
420 if (messageID >= 0)
421 {
422 buffer.append(", messageID=");
423 buffer.append(messageID);
424 }
425
426 if (activeFileName != null)
427 {
428 buffer.append(", activeFileName='");
429 buffer.append(activeFileName);
430 buffer.append('\'');
431 }
432
433 if (! baselineFileNames.isEmpty())
434 {
435 buffer.append(", baselineFileNames={");
436
437 final Iterator<String> iterator = baselineFileNames.iterator();
438 while (iterator.hasNext())
439 {
440 buffer.append('\'');
441 buffer.append(iterator.next());
442 buffer.append('\'');
443 if (iterator.hasNext())
444 {
445 buffer.append(',');
446 }
447 }
448
449 buffer.append('}');
450 }
451
452 if (! archivedFileNames.isEmpty())
453 {
454 buffer.append(", archivedFileNames={");
455
456 final Iterator<String> iterator = archivedFileNames.iterator();
457 while (iterator.hasNext())
458 {
459 buffer.append('\'');
460 buffer.append(iterator.next());
461 buffer.append('\'');
462 if (iterator.hasNext())
463 {
464 buffer.append(',');
465 }
466 }
467
468 buffer.append('}');
469 }
470
471 final String diagnosticMessage = getDiagnosticMessage();
472 if (diagnosticMessage != null)
473 {
474 buffer.append(", diagnosticMessage='");
475 buffer.append(diagnosticMessage);
476 buffer.append('\'');
477 }
478
479 final String matchedDN = getMatchedDN();
480 if (matchedDN != null)
481 {
482 buffer.append(", matchedDN='");
483 buffer.append(matchedDN);
484 buffer.append('\'');
485 }
486
487 final String[] referralURLs = getReferralURLs();
488 if (referralURLs.length > 0)
489 {
490 buffer.append(", referralURLs={");
491 for (int i=0; i < referralURLs.length; i++)
492 {
493 if (i > 0)
494 {
495 buffer.append(", ");
496 }
497
498 buffer.append('\'');
499 buffer.append(referralURLs[i]);
500 buffer.append('\'');
501 }
502 buffer.append('}');
503 }
504
505 final Control[] responseControls = getResponseControls();
506 if (responseControls.length > 0)
507 {
508 buffer.append(", responseControls={");
509 for (int i=0; i < responseControls.length; i++)
510 {
511 if (i > 0)
512 {
513 buffer.append(", ");
514 }
515
516 buffer.append(responseControls[i]);
517 }
518 buffer.append('}');
519 }
520
521 buffer.append(')');
522 }
523 }