001/* 002 * Copyright 2016-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2016-2024 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) 2016-2024 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.experimental; 037 038 039 040import java.util.Collections; 041import java.util.List; 042 043import com.unboundid.ldap.sdk.DereferencePolicy; 044import com.unboundid.ldap.sdk.Entry; 045import com.unboundid.ldap.sdk.Filter; 046import com.unboundid.ldap.sdk.LDAPException; 047import com.unboundid.ldap.sdk.OperationType; 048import com.unboundid.ldap.sdk.ResultCode; 049import com.unboundid.ldap.sdk.SearchRequest; 050import com.unboundid.ldap.sdk.SearchScope; 051import com.unboundid.util.Debug; 052import com.unboundid.util.NotMutable; 053import com.unboundid.util.NotNull; 054import com.unboundid.util.Nullable; 055import com.unboundid.util.StaticUtils; 056import com.unboundid.util.ThreadSafety; 057import com.unboundid.util.ThreadSafetyLevel; 058 059import static com.unboundid.ldap.sdk.experimental.ExperimentalMessages.*; 060 061 062 063/** 064 * This class represents an entry that holds information about a search 065 * operation processed by an LDAP server, as per the specification described in 066 * draft-chu-ldap-logschema-00. 067 */ 068@NotMutable() 069@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 070public final class DraftChuLDAPLogSchema00SearchEntry 071 extends DraftChuLDAPLogSchema00Entry 072{ 073 /** 074 * The name of the attribute used to hold the alias dereference policy. 075 */ 076 @NotNull public static final String ATTR_DEREFERENCE_POLICY = 077 "reqDerefAliases"; 078 079 080 081 /** 082 * The name of the attribute used to hold the number of entries returned. 083 */ 084 @NotNull public static final String ATTR_ENTRIES_RETURNED = "reqEntries"; 085 086 087 088 /** 089 * The name of the attribute used to hold the search filter. 090 */ 091 @NotNull public static final String ATTR_FILTER = "reqFilter"; 092 093 094 095 /** 096 * The name of the attribute used to hold a requested attribute. 097 */ 098 @NotNull public static final String ATTR_REQUESTED_ATTRIBUTE = "reqAttr"; 099 100 101 102 /** 103 * The name of the attribute used to hold the search scope. 104 */ 105 @NotNull public static final String ATTR_SCOPE = "reqScope"; 106 107 108 109 /** 110 * The name of the attribute used to hold the requested size limit. 111 */ 112 @NotNull public static final String ATTR_SIZE_LIMIT = "reqSizeLimit"; 113 114 115 116 /** 117 * The name of the attribute used to hold the requested time limit in seconds. 118 */ 119 @NotNull public static final String ATTR_TIME_LIMIT_SECONDS = "reqTimeLimit"; 120 121 122 123 /** 124 * The name of the attribute used to hold the value of the typesOnly flag. 125 */ 126 @NotNull public static final String ATTR_TYPES_ONLY = "reqAttrsOnly"; 127 128 129 130 /** 131 * The serial version UID for this serializable class. 132 */ 133 private static final long serialVersionUID = 948178493925578134L; 134 135 136 137 // The types only flag. 138 private final boolean typesOnly; 139 140 // The alias dereference policy. 141 @NotNull private final DereferencePolicy dereferencePolicy; 142 143 // The search filter. 144 @Nullable private final Filter filter; 145 146 // The number of entries returned. 147 @Nullable private final Integer entriesReturned; 148 149 // The requested size limit. 150 @Nullable private final Integer requestedSizeLimit; 151 152 // The requested time limit in seconds. 153 @Nullable private final Integer requestedTimeLimitSeconds; 154 155 // The list of requested attributes. 156 @NotNull private final List<String> requestedAttributes; 157 158 // The search scope. 159 @NotNull private final SearchScope scope; 160 161 162 163 /** 164 * Creates a new instance of this search access log entry from the provided 165 * entry. 166 * 167 * @param entry The entry used to create this search access log entry. 168 * 169 * @throws LDAPException If the provided entry cannot be decoded as a valid 170 * search access log entry as per the specification 171 * contained in draft-chu-ldap-logschema-00. 172 */ 173 public DraftChuLDAPLogSchema00SearchEntry(@NotNull final Entry entry) 174 throws LDAPException 175 { 176 super(entry, OperationType.SEARCH); 177 178 179 // Get the scope. 180 final String scopeStr = entry.getAttributeValue(ATTR_SCOPE); 181 if (scopeStr == null) 182 { 183 throw new LDAPException(ResultCode.DECODING_ERROR, 184 ERR_LOGSCHEMA_DECODE_MISSING_REQUIRED_ATTR.get(entry.getDN(), 185 ATTR_SCOPE)); 186 } 187 188 final String lowerScope = StaticUtils.toLowerCase(scopeStr); 189 if (lowerScope.equals("base")) 190 { 191 scope = SearchScope.BASE; 192 } 193 else if (lowerScope.equals("one")) 194 { 195 scope = SearchScope.ONE; 196 } 197 else if (lowerScope.equals("sub")) 198 { 199 scope = SearchScope.SUB; 200 } 201 else if (lowerScope.equals("subord")) 202 { 203 scope = SearchScope.SUBORDINATE_SUBTREE; 204 } 205 else 206 { 207 throw new LDAPException(ResultCode.DECODING_ERROR, 208 ERR_LOGSCHEMA_DECODE_SEARCH_SCOPE_ERROR.get(entry.getDN(), 209 ATTR_SCOPE, scopeStr)); 210 } 211 212 213 // Get the dereference policy. 214 final String derefStr = entry.getAttributeValue(ATTR_DEREFERENCE_POLICY); 215 if (derefStr == null) 216 { 217 throw new LDAPException(ResultCode.DECODING_ERROR, 218 ERR_LOGSCHEMA_DECODE_MISSING_REQUIRED_ATTR.get(entry.getDN(), 219 ATTR_DEREFERENCE_POLICY)); 220 } 221 222 final String lowerDeref = StaticUtils.toLowerCase(derefStr); 223 if (lowerDeref.equals("never")) 224 { 225 dereferencePolicy = DereferencePolicy.NEVER; 226 } 227 else if (lowerDeref.equals("searching")) 228 { 229 dereferencePolicy = DereferencePolicy.SEARCHING; 230 } 231 else if (lowerDeref.equals("finding")) 232 { 233 dereferencePolicy = DereferencePolicy.FINDING; 234 } 235 else if (lowerDeref.equals("always")) 236 { 237 dereferencePolicy = DereferencePolicy.ALWAYS; 238 } 239 else 240 { 241 throw new LDAPException(ResultCode.DECODING_ERROR, 242 ERR_LOGSCHEMA_DECODE_SEARCH_DEREF_ERROR.get(entry.getDN(), 243 ATTR_DEREFERENCE_POLICY, derefStr)); 244 } 245 246 247 // Get the typesOnly flag. 248 final String typesOnlyStr = entry.getAttributeValue(ATTR_TYPES_ONLY); 249 if (typesOnlyStr == null) 250 { 251 throw new LDAPException(ResultCode.DECODING_ERROR, 252 ERR_LOGSCHEMA_DECODE_MISSING_REQUIRED_ATTR.get(entry.getDN(), 253 ATTR_TYPES_ONLY)); 254 } 255 256 final String lowerTypesOnly = StaticUtils.toLowerCase(typesOnlyStr); 257 if (lowerTypesOnly.equals("true")) 258 { 259 typesOnly = true; 260 } 261 else if (lowerTypesOnly.equals("false")) 262 { 263 typesOnly = false; 264 } 265 else 266 { 267 throw new LDAPException(ResultCode.DECODING_ERROR, 268 ERR_LOGSCHEMA_DECODE_SEARCH_TYPES_ONLY_ERROR.get(entry.getDN(), 269 ATTR_TYPES_ONLY, typesOnlyStr)); 270 } 271 272 273 // Get the filter. For some strange reason, this is allowed to be 274 // undefined. 275 final String filterStr = entry.getAttributeValue(ATTR_FILTER); 276 if (filterStr == null) 277 { 278 filter = null; 279 } 280 else 281 { 282 try 283 { 284 filter = Filter.create(filterStr); 285 } 286 catch (final Exception e) 287 { 288 Debug.debugException(e); 289 throw new LDAPException(ResultCode.DECODING_ERROR, 290 ERR_LOGSCHEMA_DECODE_SEARCH_FILTER_ERROR.get(entry.getDN(), 291 ATTR_FILTER, filterStr), 292 e); 293 } 294 } 295 296 297 // Get the set of requested attributes. 298 final String[] requestedAttrArray = 299 entry.getAttributeValues(ATTR_REQUESTED_ATTRIBUTE); 300 if ((requestedAttrArray == null) || (requestedAttrArray.length == 0)) 301 { 302 requestedAttributes = Collections.emptyList(); 303 } 304 else 305 { 306 requestedAttributes = 307 Collections.unmodifiableList(StaticUtils.toList(requestedAttrArray)); 308 } 309 310 311 // Get the requested size limit. 312 final String sizeLimitStr = entry.getAttributeValue(ATTR_SIZE_LIMIT); 313 if (sizeLimitStr == null) 314 { 315 requestedSizeLimit = null; 316 } 317 else 318 { 319 try 320 { 321 requestedSizeLimit = Integer.parseInt(sizeLimitStr); 322 } 323 catch (final Exception e) 324 { 325 Debug.debugException(e); 326 throw new LDAPException(ResultCode.DECODING_ERROR, 327 ERR_LOGSCHEMA_DECODE_SEARCH_INT_ERROR.get(entry.getDN(), 328 ATTR_SIZE_LIMIT, sizeLimitStr), 329 e); 330 } 331 } 332 333 334 // Get the requested time limit. 335 final String timeLimitStr = 336 entry.getAttributeValue(ATTR_TIME_LIMIT_SECONDS); 337 if (timeLimitStr == null) 338 { 339 requestedTimeLimitSeconds = null; 340 } 341 else 342 { 343 try 344 { 345 requestedTimeLimitSeconds = Integer.parseInt(timeLimitStr); 346 } 347 catch (final Exception e) 348 { 349 Debug.debugException(e); 350 throw new LDAPException(ResultCode.DECODING_ERROR, 351 ERR_LOGSCHEMA_DECODE_SEARCH_INT_ERROR.get(entry.getDN(), 352 ATTR_TIME_LIMIT_SECONDS, timeLimitStr), 353 e); 354 } 355 } 356 357 358 // Get the number of entries returned. 359 final String entriesReturnedStr = 360 entry.getAttributeValue(ATTR_ENTRIES_RETURNED); 361 if (entriesReturnedStr == null) 362 { 363 entriesReturned = null; 364 } 365 else 366 { 367 try 368 { 369 entriesReturned = Integer.parseInt(entriesReturnedStr); 370 } 371 catch (final Exception e) 372 { 373 Debug.debugException(e); 374 throw new LDAPException(ResultCode.DECODING_ERROR, 375 ERR_LOGSCHEMA_DECODE_SEARCH_INT_ERROR.get(entry.getDN(), 376 ATTR_ENTRIES_RETURNED, entriesReturnedStr), 377 e); 378 } 379 } 380 } 381 382 383 384 /** 385 * Retrieves the scope for the search request described by this search access 386 * log entry. 387 * 388 * @return The scope for the search request described by this search access 389 * log entry. 390 */ 391 @NotNull() 392 public SearchScope getScope() 393 { 394 return scope; 395 } 396 397 398 399 /** 400 * Retrieves the alias dereference policy for the search request described by 401 * this search access log entry. 402 * 403 * @return The alias dereference policy for the search request described by 404 * this search access log entry. 405 */ 406 @NotNull() 407 public DereferencePolicy getDereferencePolicy() 408 { 409 return dereferencePolicy; 410 } 411 412 413 414 /** 415 * Retrieves the value of the typesOnly flag for the search request described 416 * by this search access log entry. 417 * 418 * @return The value of the typesOnly flag for the search request described 419 * by this search access log entry. 420 */ 421 public boolean typesOnly() 422 { 423 return typesOnly; 424 } 425 426 427 428 /** 429 * Retrieves the filter for the search request described by this search access 430 * log entry, if available. 431 * 432 * @return The filter for the search request described by this search access 433 * log entry, or {@code null} if no filter was included in the access 434 * log entry. 435 */ 436 @Nullable() 437 public Filter getFilter() 438 { 439 return filter; 440 } 441 442 443 444 /** 445 * Retrieves the requested size limit for the search request described by this 446 * search access log entry, if available. 447 * 448 * @return The requested size limit for the search request described by this 449 * search access log entry, or {@code null} if no size limit was 450 * included in the access log entry. 451 */ 452 @Nullable() 453 public Integer getRequestedSizeLimit() 454 { 455 return requestedSizeLimit; 456 } 457 458 459 460 /** 461 * Retrieves the requested time limit (in seconds) for the search request 462 * described by this search access log entry, if available. 463 * 464 * @return The requested time limit (in seconds) for the search request 465 * described by this search access log entry, or {@code null} if no 466 * time limit was included in the access log entry. 467 */ 468 @Nullable() 469 public Integer getRequestedTimeLimitSeconds() 470 { 471 return requestedTimeLimitSeconds; 472 } 473 474 475 476 /** 477 * Retrieves the requested attributes for the search request described by this 478 * search access log entry, if available. 479 * 480 * @return The requested attributes for the search request described by this 481 * search access log entry, or an empty list if no requested 482 * attributes were included in the access log entry. 483 */ 484 @NotNull() 485 public List<String> getRequestedAttributes() 486 { 487 return requestedAttributes; 488 } 489 490 491 492 /** 493 * Retrieves the number of entries returned to the client in response to the 494 * search request described by this search access log entry, if available. 495 * 496 * @return The number of entries returned to the client in response to the 497 * search request described by this search access log entry, or 498 * {@code null} if the number of entries returned was not included in 499 * the access log entry. 500 */ 501 @Nullable() 502 public Integer getEntriesReturned() 503 { 504 return entriesReturned; 505 } 506 507 508 509 /** 510 * Retrieves a {@code SearchRequest} created from this search access log 511 * entry. If the size limit or time limit was not present in the entry, a 512 * default of zero will be used. If the filter was not present in the entry, 513 * a default of "(objectClass=*)" will be used. 514 * 515 * @return The {@code SearchRequest} created from this search access log 516 * entry. 517 */ 518 @NotNull() 519 public SearchRequest toSearchRequest() 520 { 521 final int sizeLimit = 522 ((requestedSizeLimit == null) 523 ? 0 524 : requestedSizeLimit); 525 final int timeLimit = 526 ((requestedTimeLimitSeconds == null) 527 ? 0 528 : requestedTimeLimitSeconds); 529 final Filter f = 530 ((filter == null) 531 ? Filter.createPresenceFilter("objectClass") 532 : filter); 533 534 final String[] attrArray = 535 requestedAttributes.toArray(StaticUtils.NO_STRINGS); 536 537 final SearchRequest searchRequest = new SearchRequest(getTargetEntryDN(), 538 scope, dereferencePolicy, sizeLimit, timeLimit, typesOnly, f, 539 attrArray); 540 searchRequest.setControls(getRequestControlArray()); 541 return searchRequest; 542 } 543}