001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.api.ldap.codec.api; 021 022 023import org.apache.directory.api.asn1.DecoderException; 024import org.apache.directory.api.asn1.ber.AbstractContainer; 025import org.apache.directory.api.asn1.ber.tlv.TLV; 026import org.apache.directory.api.ldap.codec.LdapMessageGrammar; 027import org.apache.directory.api.ldap.codec.LdapStatesEnum; 028import org.apache.directory.api.ldap.codec.search.ConnectorFilter; 029import org.apache.directory.api.ldap.codec.search.Filter; 030import org.apache.directory.api.ldap.codec.search.PresentFilter; 031import org.apache.directory.api.ldap.model.entry.Attribute; 032import org.apache.directory.api.ldap.model.entry.Modification; 033import org.apache.directory.api.ldap.model.message.Control; 034import org.apache.directory.api.ldap.model.message.ExtendedResponse; 035import org.apache.directory.api.ldap.model.message.LdapResult; 036import org.apache.directory.api.ldap.model.message.Message; 037import org.apache.directory.api.ldap.model.message.ResultResponse; 038 039 040/** 041 * The LdapMessage container stores all the messages decoded by the Asn1Decoder. 042 * When dealing with an encoding PDU, we will obtain a LdapMessage in the 043 * container. 044 * 045 * @param <E> The decorated message 046 * 047 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 048 */ 049public class LdapMessageContainer<E extends Message> extends AbstractContainer 050{ 051 /** The Message being decoded */ 052 private E message; 053 054 /** checks if attribute is binary */ 055 private BinaryAttributeDetector binaryAttributeDetector; 056 057 /** The message ID */ 058 private int messageId; 059 060 /** The current control */ 061 private Control currentControl; 062 063 /** The current control factory, if any */ 064 private ControlFactory<?> controlFactory; 065 066 /** The current Intermediate response factory */ 067 private IntermediateOperationFactory intermediateFactory; 068 069 /** The current Extended operation factory */ 070 private ExtendedOperationFactory extendedFactory; 071 072 /** The codec service */ 073 private final LdapApiService codec; 074 075 /** The current LdapResult for a response */ 076 private LdapResult ldapResult; 077 078 /** The current attribute being decoded */ 079 private Attribute currentAttribute; 080 081 /** A local storage for the MODIFY operation */ 082 private Modification currentModification; 083 084 /** The SearchRequest TLV id */ 085 private int tlvId; 086 087 /** A temporary storage for a terminal Filter */ 088 private Filter terminalFilter; 089 090 /** The current filter. This is used while decoding a PDU */ 091 private Filter currentFilter; 092 093 /** The global filter. This is used while decoding a PDU */ 094 private Filter topFilter; 095 096 097 /** 098 * Creates a new LdapMessageContainer object. We will store ten grammars, 099 * it's enough ... 100 * 101 * @param codec The LDAP service instance 102 */ 103 public LdapMessageContainer( LdapApiService codec ) 104 { 105 this( codec, new DefaultConfigurableBinaryAttributeDetector() ); 106 } 107 108 109 /** 110 * Creates a new LdapMessageContainer object. 111 * 112 * @param codec The LDAP service instance 113 * @param binaryAttributeDetector checks if an attribute is binary 114 */ 115 public LdapMessageContainer( LdapApiService codec, BinaryAttributeDetector binaryAttributeDetector ) 116 { 117 super(); 118 this.codec = codec; 119 setGrammar( LdapMessageGrammar.getInstance() ); 120 this.binaryAttributeDetector = binaryAttributeDetector; 121 setTransition( LdapStatesEnum.START_STATE ); 122 } 123 124 125 /** 126 * Gets the {@link LdapApiService} associated with this Container. 127 * 128 * @return The LDAP service instance 129 */ 130 public LdapApiService getLdapCodecService() 131 { 132 return codec; 133 } 134 135 136 /** 137 * @return Returns the ldapMessage. 138 */ 139 public E getMessage() 140 { 141 return message; 142 } 143 144 145 /** 146 * Set a Message Object into the container. It will be completed by the 147 * ldapDecoder. 148 * 149 * @param message The message to set. 150 */ 151 public void setMessage( E message ) 152 { 153 this.message = message; 154 } 155 156 157 /** 158 * {@inheritDoc} 159 */ 160 @Override 161 public void clean() 162 { 163 super.clean(); 164 165 messageId = -1; 166 tlvId = -1; 167 message = null; 168 ldapResult = null; 169 currentControl = null; 170 currentAttribute = null; 171 currentFilter = null; 172 terminalFilter = null; 173 topFilter = null; 174 controlFactory = null; 175 intermediateFactory = null; 176 extendedFactory = null; 177 setDecodedBytes( 0 ); 178 } 179 180 181 /** 182 * @return Returns true if the attribute is binary. 183 * @param id checks if an attribute id is binary 184 */ 185 public boolean isBinary( String id ) 186 { 187 return binaryAttributeDetector.isBinary( id ); 188 } 189 190 191 /** 192 * @return The message ID 193 */ 194 public int getMessageId() 195 { 196 return messageId; 197 } 198 199 200 /** 201 * Set the message ID 202 * @param messageId the id of the message 203 */ 204 public void setMessageId( int messageId ) 205 { 206 this.messageId = messageId; 207 } 208 209 210 /** 211 * @return the current control being created 212 */ 213 public Control getCurrentControl() 214 { 215 return currentControl; 216 } 217 218 219 /** 220 * Store a newly created control 221 * @param currentControl The control to store 222 */ 223 public void setCurrentControl( Control currentControl ) 224 { 225 this.currentControl = currentControl; 226 } 227 228 229 /** 230 * Sets the binary attribute detector 231 * 232 * @param binaryAttributeDetector the binary attribute detector 233 */ 234 public void setBinaryAttributeDetector( BinaryAttributeDetector binaryAttributeDetector ) 235 { 236 this.binaryAttributeDetector = binaryAttributeDetector; 237 } 238 239 240 /** 241 * @return the binary attribute detector 242 */ 243 public BinaryAttributeDetector getBinaryAttributeDetector() 244 { 245 return binaryAttributeDetector; 246 } 247 248 249 /** 250 * @return the ldapResult 251 */ 252 public LdapResult getLdapResult() 253 { 254 return ldapResult; 255 } 256 257 258 /** 259 * @param ldapResult the ldapResult to set 260 */ 261 public void setLdapResult( LdapResult ldapResult ) 262 { 263 this.ldapResult = ldapResult; 264 } 265 266 267 /** 268 * @return the controlFactory 269 */ 270 public ControlFactory<?> getControlFactory() 271 { 272 return controlFactory; 273 } 274 275 276 /** 277 * @param controlFactory the controlFactory to set 278 */ 279 public void setControlFactory( ControlFactory<?> controlFactory ) 280 { 281 this.controlFactory = controlFactory; 282 } 283 284 285 /** 286 * @return the currentAttribute 287 */ 288 public Attribute getCurrentAttribute() 289 { 290 return currentAttribute; 291 } 292 293 294 /** 295 * @param currentAttribute the currentAttribute to set 296 */ 297 public void setCurrentAttribute( Attribute currentAttribute ) 298 { 299 this.currentAttribute = currentAttribute; 300 } 301 302 303 /** 304 * @return the currentModification 305 */ 306 public Modification getCurrentModification() 307 { 308 return currentModification; 309 } 310 311 312 /** 313 * @param currentModification the currentModification to set 314 */ 315 public void setCurrentModification( Modification currentModification ) 316 { 317 this.currentModification = currentModification; 318 } 319 320 321 /** 322 * Set the SearchRequest PDU TLV's Id 323 * @param tlvId The TLV id 324 */ 325 public void setTlvId( int tlvId ) 326 { 327 this.tlvId = tlvId; 328 } 329 330 331 /** 332 * @return the terminalFilter 333 */ 334 public Filter getTerminalFilter() 335 { 336 return terminalFilter; 337 } 338 339 340 /** 341 * @param terminalFilter the terminalFilter to set 342 */ 343 public void setTerminalFilter( Filter terminalFilter ) 344 { 345 this.terminalFilter = terminalFilter; 346 } 347 348 349 /** 350 * @return the currentFilter 351 */ 352 public Filter getCurrentFilter() 353 { 354 return currentFilter; 355 } 356 357 358 /** 359 * @param currentFilter the currentFilter to set 360 */ 361 public void setCurrentFilter( Filter currentFilter ) 362 { 363 this.currentFilter = currentFilter; 364 } 365 366 367 /** 368 * Add a current filter. We have two cases : 369 * - there is no previous current filter : the filter 370 * is the top level filter 371 * - there is a previous current filter : the filter is added 372 * to the currentFilter set, and the current filter is changed 373 * 374 * In any case, the previous current filter will always be a 375 * ConnectorFilter when this method is called. 376 * 377 * @param localFilter The filter to set. 378 * @throws DecoderException If the filter is invalid 379 */ 380 public void addCurrentFilter( Filter localFilter ) throws DecoderException 381 { 382 if ( currentFilter != null ) 383 { 384 // Ok, we have a parent. The new Filter will be added to 385 // this parent, and will become the currentFilter if it's a connector. 386 ( ( ConnectorFilter ) currentFilter ).addFilter( localFilter ); 387 localFilter.setParent( currentFilter, currentFilter.getTlvId() ); 388 389 if ( localFilter instanceof ConnectorFilter ) 390 { 391 currentFilter = localFilter; 392 } 393 } 394 else 395 { 396 // No parent. This Filter will become the root. 397 currentFilter = localFilter; 398 currentFilter.setParent( null, tlvId ); 399 topFilter = localFilter; 400 } 401 } 402 403 404 /** 405 * This method is used to clear the filter's stack for terminated elements. An element 406 * is considered as terminated either if : 407 * - it's a final element (ie an element which cannot contains a Filter) 408 * - its current length equals its expected length. 409 */ 410 public void unstackFilters() 411 { 412 TLV tlv = getCurrentTLV(); 413 TLV localParent = tlv.getParent(); 414 Filter localFilter = terminalFilter; 415 416 // The parent has been completed, so fold it 417 while ( ( localParent != null ) && ( localParent.getExpectedLength() == 0 ) ) 418 { 419 int parentTlvId = localFilter.getParent() != null ? localFilter.getParent().getTlvId() : localFilter 420 .getParentTlvId(); 421 422 if ( localParent.getId() != parentTlvId ) 423 { 424 localParent = localParent.getParent(); 425 } 426 else 427 { 428 Filter filterParent = localFilter.getParent(); 429 430 // We have a special case with PresentFilter, which has not been 431 // pushed on the stack, so we need to get its parent's parent 432 if ( localFilter instanceof PresentFilter ) 433 { 434 if ( filterParent == null ) 435 { 436 // We don't have parent, get out 437 break; 438 } 439 440 filterParent = filterParent.getParent(); 441 } 442 else 443 { 444 filterParent = filterParent.getParent(); 445 } 446 447 if ( filterParent != null ) 448 { 449 // The parent is a filter ; it will become the new currentFilter 450 // and we will loop again. 451 localFilter = currentFilter; 452 currentFilter = filterParent; 453 localParent = localParent.getParent(); 454 } 455 else 456 { 457 // We can stop the recursion, we have reached the searchResult Object 458 break; 459 } 460 } 461 } 462 } 463 464 465 /** 466 * Copy the LdapResult element from a opaque response to a newly created 467 * extendedResponse 468 * 469 * @param resultResponse The original response 470 * @param extendedResponse The newly created ExtendedResponse 471 */ 472 public static void copyLdapResult( ResultResponse resultResponse, ExtendedResponse extendedResponse ) 473 { 474 extendedResponse.getLdapResult().setDiagnosticMessage( resultResponse.getLdapResult().getDiagnosticMessage() ); 475 extendedResponse.getLdapResult().setMatchedDn( resultResponse.getLdapResult().getMatchedDn() ); 476 extendedResponse.getLdapResult().setReferral( resultResponse.getLdapResult().getReferral() ); 477 extendedResponse.getLdapResult().setResultCode( resultResponse.getLdapResult().getResultCode() ); 478 } 479 480 481 /** 482 * @return the topFilter 483 */ 484 public Filter getTopFilter() 485 { 486 return topFilter; 487 } 488 489 490 /** 491 * @param topFilter the topFilter to set 492 */ 493 public void setTopFilter( Filter topFilter ) 494 { 495 this.topFilter = topFilter; 496 } 497 498 499 /** 500 * @return the tlvId 501 */ 502 public int getTlvId() 503 { 504 return tlvId; 505 } 506 507 508 /** 509 * @return the intermediateFactory 510 */ 511 public IntermediateOperationFactory getIntermediateFactory() 512 { 513 return intermediateFactory; 514 } 515 516 517 /** 518 * @param intermediateFactory the intermediateFactory to set 519 */ 520 public void setIntermediateFactory( IntermediateOperationFactory intermediateFactory ) 521 { 522 this.intermediateFactory = intermediateFactory; 523 } 524 525 526 /** 527 * @return the extendedFactory 528 */ 529 public ExtendedOperationFactory getExtendedFactory() 530 { 531 return extendedFactory; 532 } 533 534 535 /** 536 * @param extendedFactory the extendedFactory to set 537 */ 538 public void setExtendedFactory( ExtendedOperationFactory extendedFactory ) 539 { 540 this.extendedFactory = extendedFactory; 541 } 542}