001 /*
002 * Copyright 2008-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.Date;
029 import java.util.Iterator;
030 import java.util.List;
031
032 import com.unboundid.asn1.ASN1Element;
033 import com.unboundid.asn1.ASN1Enumerated;
034 import com.unboundid.asn1.ASN1OctetString;
035 import com.unboundid.asn1.ASN1Sequence;
036 import com.unboundid.ldap.sdk.Control;
037 import com.unboundid.ldap.sdk.ExtendedResult;
038 import com.unboundid.ldap.sdk.LDAPException;
039 import com.unboundid.ldap.sdk.ResultCode;
040 import com.unboundid.util.NotMutable;
041 import com.unboundid.util.StaticUtils;
042 import com.unboundid.util.ThreadSafety;
043 import com.unboundid.util.ThreadSafetyLevel;
044
045 import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
046 import static com.unboundid.util.Debug.*;
047
048
049
050 /**
051 * <BLOCKQUOTE>
052 * <B>NOTE:</B> This class is part of the Commercial Edition of the UnboundID
053 * LDAP SDK for Java. It is not available for use in applications that
054 * include only the Standard Edition of the LDAP SDK, and is not supported for
055 * use in conjunction with non-UnboundID products.
056 * </BLOCKQUOTE>
057 * This class provides an implementation of an extended result that holds
058 * information about the response returned from a
059 * {@link GetSubtreeAccessibilityExtendedRequest}. It has an OID of
060 * 1.3.6.1.4.1.30221.1.6.21, and successful responses will have a value with the
061 * following encoding:
062 * <BR><BR>
063 * <PRE>
064 * GetSubtreeAccessibilityResultValue ::= SEQUENCE OF SEQUENCE {
065 * subtreeBaseDN [0] LDAPDN,
066 * subtreeAccessibility [1] ENUMERATED {
067 * accessible (0),
068 * read-only-bind-allowed (1),
069 * read-only-bind-denied (2),
070 * hidden (3),
071 * ... },
072 * bypassUserDN [2] LDAPDN OPTIONAL,
073 * effectiveTime [3] OCTET STRING,
074 * ... }
075 * </PRE>
076 */
077 @NotMutable()
078 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
079 public final class GetSubtreeAccessibilityExtendedResult
080 extends ExtendedResult
081 {
082 /**
083 * The OID (1.3.6.1.4.1.30221.1.6.21) for the get subtree accessibility
084 * extended result.
085 */
086 public static final String GET_SUBTREE_ACCESSIBILITY_RESULT_OID =
087 "1.3.6.1.4.1.30221.1.6.21";
088
089
090
091 /**
092 * The BER type for the element that holds the base DN for a subtree
093 * accessibility restriction.
094 */
095 private static final byte TYPE_BASE_DN = (byte) 0x80;
096
097
098
099 /**
100 * The BER type for the element that holds the accessibility state for a
101 * subtree accessibility restriction.
102 */
103 private static final byte TYPE_STATE = (byte) 0x81;
104
105
106
107 /**
108 * The BER type for the element that holds the bypass user DN for a subtree
109 * accessibility restriction.
110 */
111 private static final byte TYPE_BYPASS_USER = (byte) 0x82;
112
113
114
115 /**
116 * The BER type for the element that holds the effective time for a subtree
117 * accessibility restriction.
118 */
119 private static final byte TYPE_EFFECTIVE_TIME = (byte) 0x83;
120
121
122
123 /**
124 * The serial version UID for this serializable class.
125 */
126 private static final long serialVersionUID = -3163306122775326749L;
127
128
129
130 // A list of the subtree accessibility restrictions defined in the server.
131 private final List<SubtreeAccessibilityRestriction> accessibilityRestrictions;
132
133
134
135 /**
136 * Creates a new get subtree accessibility extended result from the provided
137 * generic extended result.
138 *
139 * @param extendedResult The generic extended result to be decoded.
140 *
141 * @throws LDAPException If a problem occurs while attempting to decode the
142 * provided extended result as a get connection ID
143 * result.
144 */
145 public GetSubtreeAccessibilityExtendedResult(
146 final ExtendedResult extendedResult)
147 throws LDAPException
148 {
149 super(extendedResult);
150
151 final ASN1OctetString value = extendedResult.getValue();
152 if (value == null)
153 {
154 accessibilityRestrictions = null;
155 return;
156 }
157
158 try
159 {
160 final ASN1Element[] restrictionElements =
161 ASN1Sequence.decodeAsSequence(value.getValue()).elements();
162 final ArrayList<SubtreeAccessibilityRestriction> restrictionList =
163 new ArrayList<SubtreeAccessibilityRestriction>(
164 restrictionElements.length);
165
166 for (final ASN1Element e : restrictionElements)
167 {
168 String baseDN = null;
169 SubtreeAccessibilityState state = null;
170 String bypassDN = null;
171 Date effectiveTime = null;
172
173 for (final ASN1Element re : ASN1Sequence.decodeAsSequence(e).elements())
174 {
175 switch (re.getType())
176 {
177 case TYPE_BASE_DN:
178 baseDN = ASN1OctetString.decodeAsOctetString(re).stringValue();
179 break;
180 case TYPE_STATE:
181 state = SubtreeAccessibilityState.valueOf(
182 ASN1Enumerated.decodeAsEnumerated(re).intValue());
183 if (state == null)
184 {
185 throw new LDAPException(ResultCode.DECODING_ERROR,
186 ERR_GET_SUBTREE_ACCESSIBILITY_RESULT_UNEXPECTED_STATE.get(
187 ASN1Enumerated.decodeAsEnumerated(re).intValue()));
188 }
189 break;
190 case TYPE_BYPASS_USER:
191 bypassDN = ASN1OctetString.decodeAsOctetString(re).stringValue();
192 break;
193 case TYPE_EFFECTIVE_TIME:
194 effectiveTime = StaticUtils.decodeGeneralizedTime(
195 ASN1OctetString.decodeAsOctetString(re).stringValue());
196 break;
197 default:
198 throw new LDAPException(ResultCode.DECODING_ERROR,
199 ERR_GET_SUBTREE_ACCESSIBILITY_RESULT_UNEXPECTED_TYPE.get(
200 StaticUtils.toHex(re.getType())));
201 }
202 }
203
204 if (baseDN == null)
205 {
206 throw new LDAPException(ResultCode.DECODING_ERROR,
207 ERR_GET_SUBTREE_ACCESSIBILITY_RESULT_MISSING_BASE.get());
208 }
209
210 if (state == null)
211 {
212 throw new LDAPException(ResultCode.DECODING_ERROR,
213 ERR_GET_SUBTREE_ACCESSIBILITY_RESULT_MISSING_STATE.get());
214 }
215
216 if (effectiveTime == null)
217 {
218 throw new LDAPException(ResultCode.DECODING_ERROR,
219 ERR_GET_SUBTREE_ACCESSIBILITY_RESULT_MISSING_TIME.get());
220 }
221
222 restrictionList.add(new SubtreeAccessibilityRestriction(baseDN, state,
223 bypassDN, effectiveTime));
224 }
225
226 accessibilityRestrictions = Collections.unmodifiableList(restrictionList);
227 }
228 catch (final LDAPException le)
229 {
230 debugException(le);
231 throw le;
232 }
233 catch (Exception e)
234 {
235 debugException(e);
236 throw new LDAPException(ResultCode.DECODING_ERROR,
237 ERR_GET_SUBTREE_ACCESSIBILITY_RESULT_DECODE_ERROR.get(
238 StaticUtils.getExceptionMessage(e)),
239 e);
240 }
241 }
242
243
244
245 /**
246 * Creates a new get subtree accessibility extended result with the provided
247 * information.
248 *
249 * @param messageID The message ID for the LDAP message that is
250 * associated with this LDAP result.
251 * @param resultCode The result code from the response.
252 * @param diagnosticMessage The diagnostic message from the response, if
253 * available.
254 * @param matchedDN The matched DN from the response, if available.
255 * @param referralURLs The set of referral URLs from the response, if
256 * available.
257 * @param restrictions The set of subtree accessibility restrictions
258 * to include in the response. It may be
259 * {@code null} if this represents an error
260 * response, or it may be empty if there are no
261 * subtree accessibility restrictions defined in
262 * the server.
263 * @param responseControls The set of controls from the response, if
264 * available.
265 */
266 public GetSubtreeAccessibilityExtendedResult(final int messageID,
267 final ResultCode resultCode, final String diagnosticMessage,
268 final String matchedDN, final String[] referralURLs,
269 final Collection<SubtreeAccessibilityRestriction> restrictions,
270 final Control... responseControls)
271 {
272 super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
273 null, encodeValue(restrictions), responseControls);
274
275 if (restrictions == null)
276 {
277 accessibilityRestrictions = null;
278 }
279 else
280 {
281 accessibilityRestrictions = Collections.unmodifiableList(
282 new ArrayList<SubtreeAccessibilityRestriction>(restrictions));
283 }
284 }
285
286
287
288 /**
289 * Encodes the value for this extended result using the provided information.
290 *
291 * @param restrictions The set of subtree accessibility restrictions to
292 * include in the response. It may be {@code null} if
293 * this represents an error response, or it may be empty
294 * if there are no subtree accessibility restrictions
295 * defined in the server.
296 *
297 * @return An ASN.1 octet string containing the properly-encoded value, or
298 * {@code null} if there should be no value.
299 */
300 private static ASN1OctetString encodeValue(
301 final Collection<SubtreeAccessibilityRestriction> restrictions)
302 {
303 if (restrictions == null)
304 {
305 return null;
306 }
307
308 final ArrayList<ASN1Element> elements =
309 new ArrayList<ASN1Element>(restrictions.size());
310 for (final SubtreeAccessibilityRestriction r : restrictions)
311 {
312 final ArrayList<ASN1Element> restrictionElements =
313 new ArrayList<ASN1Element>(4);
314 restrictionElements.add(new ASN1OctetString(TYPE_BASE_DN,
315 r.getSubtreeBaseDN()));
316 restrictionElements.add(new ASN1Enumerated(TYPE_STATE,
317 r.getAccessibilityState().intValue()));
318
319 if (r.getBypassUserDN() != null)
320 {
321 restrictionElements.add(new ASN1OctetString(TYPE_BYPASS_USER,
322 r.getBypassUserDN()));
323 }
324
325 restrictionElements.add(new ASN1OctetString(TYPE_EFFECTIVE_TIME,
326 StaticUtils.encodeGeneralizedTime(r.getEffectiveTime())));
327
328 elements.add(new ASN1Sequence(restrictionElements));
329 }
330
331 return new ASN1OctetString(new ASN1Sequence(elements).encode());
332 }
333
334
335
336 /**
337 * Retrieves a list of the subtree accessibility restrictions defined in the
338 * server.
339 *
340 * @return A list of the subtree accessibility restrictions defined in the
341 * server, an empty list if there are no restrictions defined, or
342 * {@code null} if no restriction data was included in the response
343 * from the server (e.g., because it was an error response).
344 */
345 public List<SubtreeAccessibilityRestriction> getAccessibilityRestrictions()
346 {
347 return accessibilityRestrictions;
348 }
349
350
351
352 /**
353 * {@inheritDoc}
354 */
355 @Override()
356 public String getExtendedResultName()
357 {
358 return INFO_EXTENDED_RESULT_NAME_GET_SUBTREE_ACCESSIBILITY.get();
359 }
360
361
362
363 /**
364 * {@inheritDoc}
365 */
366 @Override()
367 public void toString(final StringBuilder buffer)
368 {
369 buffer.append("GetSubtreeAccessibilityExtendedResult(resultCode=");
370 buffer.append(getResultCode());
371
372 final int messageID = getMessageID();
373 if (messageID >= 0)
374 {
375 buffer.append(", messageID=");
376 buffer.append(messageID);
377 }
378
379 final String diagnosticMessage = getDiagnosticMessage();
380 if (diagnosticMessage != null)
381 {
382 buffer.append(", diagnosticMessage='");
383 buffer.append(diagnosticMessage);
384 buffer.append('\'');
385 }
386
387 final String matchedDN = getMatchedDN();
388 if (matchedDN != null)
389 {
390 buffer.append(", matchedDN='");
391 buffer.append(matchedDN);
392 buffer.append('\'');
393 }
394
395 final String[] referralURLs = getReferralURLs();
396 if ((referralURLs != null) && (referralURLs.length > 0))
397 {
398 buffer.append(", referralURLs={ '");
399 for (int i=0; i < referralURLs.length; i++)
400 {
401 if (i > 0)
402 {
403 buffer.append("', '");
404 }
405 buffer.append(referralURLs[i]);
406 }
407
408 buffer.append("' }");
409 }
410
411 if (accessibilityRestrictions != null)
412 {
413 buffer.append(", accessibilityRestrictions={");
414
415 final Iterator<SubtreeAccessibilityRestriction> iterator =
416 accessibilityRestrictions.iterator();
417 while (iterator.hasNext())
418 {
419 iterator.next().toString(buffer);
420 if (iterator.hasNext())
421 {
422 buffer.append(", ");
423 }
424 }
425
426 buffer.append('}');
427 }
428
429 final Control[] controls = getResponseControls();
430 if (controls.length > 0)
431 {
432 buffer.append(", controls={");
433 for (int i=0; i < controls.length; i++)
434 {
435 if (i > 0)
436 {
437 buffer.append(", ");
438 }
439
440 buffer.append(controls[i]);
441 }
442 buffer.append('}');
443 }
444
445 buffer.append(')');
446 }
447 }