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 * http://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.osgi; 021 022 023import java.nio.ByteBuffer; 024import java.util.Collections; 025import java.util.HashMap; 026import java.util.Iterator; 027import java.util.Map; 028 029import javax.naming.NamingException; 030import javax.naming.ldap.BasicControl; 031 032import org.apache.directory.api.asn1.DecoderException; 033import org.apache.directory.api.asn1.EncoderException; 034import org.apache.directory.api.asn1.ber.Asn1Container; 035import org.apache.directory.api.ldap.codec.BasicControlDecorator; 036import org.apache.directory.api.ldap.codec.api.CodecControl; 037import org.apache.directory.api.ldap.codec.api.ControlFactory; 038import org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory; 039import org.apache.directory.api.ldap.codec.api.ExtendedRequestDecorator; 040import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator; 041import org.apache.directory.api.ldap.codec.api.LdapApiService; 042import org.apache.directory.api.ldap.codec.api.LdapMessageContainer; 043import org.apache.directory.api.ldap.codec.api.MessageDecorator; 044import org.apache.directory.api.ldap.codec.controls.cascade.CascadeFactory; 045import org.apache.directory.api.ldap.codec.controls.manageDsaIT.ManageDsaITFactory; 046import org.apache.directory.api.ldap.codec.controls.search.entryChange.EntryChangeFactory; 047import org.apache.directory.api.ldap.codec.controls.search.pagedSearch.PagedResultsFactory; 048import org.apache.directory.api.ldap.codec.controls.search.persistentSearch.PersistentSearchFactory; 049import org.apache.directory.api.ldap.codec.controls.search.subentries.SubentriesFactory; 050import org.apache.directory.api.ldap.model.message.Control; 051import org.apache.directory.api.ldap.model.message.ExtendedRequest; 052import org.apache.directory.api.ldap.model.message.ExtendedRequestImpl; 053import org.apache.directory.api.ldap.model.message.ExtendedResponse; 054import org.apache.directory.api.ldap.model.message.ExtendedResponseImpl; 055import org.apache.directory.api.ldap.model.message.Message; 056import org.apache.directory.api.ldap.model.message.controls.Cascade; 057import org.apache.directory.api.ldap.model.message.controls.EntryChange; 058import org.apache.directory.api.ldap.model.message.controls.ManageDsaIT; 059import org.apache.directory.api.ldap.model.message.controls.OpaqueControl; 060import org.apache.directory.api.ldap.model.message.controls.PagedResults; 061import org.apache.directory.api.ldap.model.message.controls.PersistentSearch; 062import org.apache.directory.api.ldap.model.message.controls.Subentries; 063import org.apache.directory.api.util.Strings; 064import org.apache.directory.api.util.exception.NotImplementedException; 065import org.apache.mina.filter.codec.ProtocolCodecFactory; 066import org.slf4j.Logger; 067import org.slf4j.LoggerFactory; 068 069 070/** 071 * The default {@link LdapApiService} implementation. 072 * 073 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 074 * @version $Rev$, $Date$ 075 */ 076public class DefaultLdapCodecService implements LdapApiService 077{ 078 /** A logger */ 079 private static final Logger LOG = LoggerFactory.getLogger( DefaultLdapCodecService.class ); 080 081 /** The map of registered {@link org.apache.directory.api.ldap.codec.api.ControlFactory}'s */ 082 protected Map<String, ControlFactory<? extends Control>> controlFactories = new HashMap<String, ControlFactory<? extends Control>>(); 083 084 /** The map of registered {@link org.apache.directory.api.ldap.codec.api.ExtendedOperationFactory}'s by request OID */ 085 protected Map<String, ExtendedOperationFactory> extendedOperationsFactories = new HashMap<String, ExtendedOperationFactory>(); 086 087 /** The registered ProtocolCodecFactory */ 088 protected ProtocolCodecFactory protocolCodecFactory; 089 090 091 /** 092 * Creates a new instance of DefaultLdapCodecService. 093 */ 094 public DefaultLdapCodecService() 095 { 096 loadStockControls(); 097 } 098 099 100 /** 101 * Loads the Controls implement out of the box in the codec. 102 */ 103 private void loadStockControls() 104 { 105 ControlFactory<Cascade> cascadeFactory = new CascadeFactory( this ); 106 controlFactories.put( cascadeFactory.getOid(), cascadeFactory ); 107 LOG.info( "Registered pre-bundled control factory: {}", cascadeFactory.getOid() ); 108 109 ControlFactory<EntryChange> entryChangeFactory = new EntryChangeFactory( this ); 110 controlFactories.put( entryChangeFactory.getOid(), entryChangeFactory ); 111 LOG.info( "Registered pre-bundled control factory: {}", entryChangeFactory.getOid() ); 112 113 ControlFactory<ManageDsaIT> manageDsaItFactory = new ManageDsaITFactory( this ); 114 controlFactories.put( manageDsaItFactory.getOid(), manageDsaItFactory ); 115 LOG.info( "Registered pre-bundled control factory: {}", manageDsaItFactory.getOid() ); 116 117 ControlFactory<PagedResults> pageResultsFactory = new PagedResultsFactory( this ); 118 controlFactories.put( pageResultsFactory.getOid(), pageResultsFactory ); 119 LOG.info( "Registered pre-bundled control factory: {}", pageResultsFactory.getOid() ); 120 121 ControlFactory<PersistentSearch> persistentSearchFactory = new PersistentSearchFactory( this ); 122 controlFactories.put( persistentSearchFactory.getOid(), persistentSearchFactory ); 123 LOG.info( "Registered pre-bundled control factory: {}", persistentSearchFactory.getOid() ); 124 125 ControlFactory<Subentries> subentriesFactory = new SubentriesFactory( this ); 126 controlFactories.put( subentriesFactory.getOid(), subentriesFactory ); 127 LOG.info( "Registered pre-bundled control factory: {}", subentriesFactory.getOid() ); 128 } 129 130 131 //------------------------------------------------------------------------- 132 // LdapCodecService implementation methods 133 //------------------------------------------------------------------------- 134 135 /** 136 * {@inheritDoc} 137 */ 138 public ControlFactory<?> registerControl( ControlFactory<?> factory ) 139 { 140 return controlFactories.put( factory.getOid(), factory ); 141 } 142 143 144 /** 145 * {@inheritDoc} 146 */ 147 public ControlFactory<?> unregisterControl( String oid ) 148 { 149 return controlFactories.remove( oid ); 150 } 151 152 153 /** 154 * {@inheritDoc} 155 */ 156 public Iterator<String> registeredControls() 157 { 158 return Collections.unmodifiableSet( controlFactories.keySet() ).iterator(); 159 } 160 161 162 /** 163 * {@inheritDoc} 164 */ 165 public boolean isControlRegistered( String oid ) 166 { 167 return controlFactories.containsKey( oid ); 168 } 169 170 171 /** 172 * {@inheritDoc} 173 */ 174 public Iterator<String> registeredExtendedRequests() 175 { 176 return Collections.unmodifiableSet( extendedOperationsFactories.keySet() ).iterator(); 177 } 178 179 180 /** 181 * {@inheritDoc} 182 */ 183 public ExtendedOperationFactory registerExtendedRequest( ExtendedOperationFactory factory ) 184 { 185 return extendedOperationsFactories.put( factory.getOid(), factory ); 186 } 187 188 189 /** 190 * {@inheritDoc} 191 */ 192 public ProtocolCodecFactory getProtocolCodecFactory() 193 { 194 return protocolCodecFactory; 195 } 196 197 198 public ProtocolCodecFactory registerProtocolCodecFactory( ProtocolCodecFactory protocolCodecFactory ) 199 { 200 ProtocolCodecFactory oldFactory = this.protocolCodecFactory; 201 this.protocolCodecFactory = protocolCodecFactory; 202 return oldFactory; 203 } 204 205 206 /** 207 * {@inheritDoc} 208 */ 209 public CodecControl<? extends Control> newControl( String oid ) 210 { 211 ControlFactory<?> factory = controlFactories.get( oid ); 212 213 if ( factory == null ) 214 { 215 return new BasicControlDecorator<Control>( this, new OpaqueControl( oid ) ); 216 } 217 218 return factory.newCodecControl(); 219 } 220 221 222 /** 223 * {@inheritDoc} 224 */ 225 @SuppressWarnings("unchecked") 226 public CodecControl<? extends Control> newControl( Control control ) 227 { 228 if ( control == null ) 229 { 230 throw new NullPointerException( "Control argument was null." ); 231 } 232 233 // protect agains being multiply decorated 234 if ( control instanceof CodecControl ) 235 { 236 return ( CodecControl<?> ) control; 237 } 238 239 @SuppressWarnings("rawtypes") 240 ControlFactory factory = controlFactories.get( control.getOid() ); 241 242 if ( factory == null ) 243 { 244 return new BasicControlDecorator<Control>( this, control ); 245 } 246 247 return factory.newCodecControl( control ); 248 } 249 250 251 /** 252 * {@inheritDoc} 253 */ 254 public javax.naming.ldap.Control toJndiControl( Control control ) throws EncoderException 255 { 256 CodecControl<? extends Control> decorator = newControl( control ); 257 ByteBuffer bb = ByteBuffer.allocate( decorator.computeLength() ); 258 decorator.encode( bb ); 259 bb.flip(); 260 BasicControl jndiControl = 261 new BasicControl( control.getOid(), control.isCritical(), bb.array() ); 262 return jndiControl; 263 } 264 265 266 /** 267 * {@inheritDoc} 268 */ 269 public Control fromJndiControl( javax.naming.ldap.Control control ) throws DecoderException 270 { 271 @SuppressWarnings("rawtypes") 272 ControlFactory factory = controlFactories.get( control.getID() ); 273 274 if ( factory == null ) 275 { 276 OpaqueControl ourControl = new OpaqueControl( control.getID() ); 277 ourControl.setCritical( control.isCritical() ); 278 BasicControlDecorator<Control> decorator = 279 new BasicControlDecorator<Control>( this, ourControl ); 280 decorator.setValue( control.getEncodedValue() ); 281 return decorator; 282 } 283 284 @SuppressWarnings("unchecked") 285 CodecControl<? extends Control> ourControl = factory.newCodecControl(); 286 ourControl.setCritical( control.isCritical() ); 287 ourControl.setValue( control.getEncodedValue() ); 288 ourControl.decode( control.getEncodedValue() ); 289 290 return ourControl; 291 } 292 293 294 /** 295 * {@inheritDoc} 296 */ 297 public Asn1Container newMessageContainer() 298 { 299 return new LdapMessageContainer<MessageDecorator<? extends Message>>( this ); 300 } 301 302 303 /** 304 * {@inheritDoc} 305 */ 306 public ExtendedOperationFactory unregisterExtendedRequest( String oid ) 307 { 308 return extendedOperationsFactories.remove( oid ); 309 } 310 311 312 /** 313 * {@inheritDoc} 314 */ 315 public javax.naming.ldap.ExtendedResponse toJndi( final ExtendedResponse modelResponse ) throws EncoderException 316 { 317 throw new NotImplementedException( "Figure out how to transform" ); 318 } 319 320 321 /** 322 * {@inheritDoc} 323 */ 324 public ExtendedResponse fromJndi( javax.naming.ldap.ExtendedResponse jndiResponse ) throws DecoderException 325 { 326 throw new NotImplementedException( "Figure out how to transform" ); 327 } 328 329 330 /** 331 * {@inheritDoc} 332 */ 333 public ExtendedRequest fromJndi( javax.naming.ldap.ExtendedRequest jndiRequest ) throws DecoderException 334 { 335 ExtendedRequestDecorator<?> decorator = 336 ( ExtendedRequestDecorator<?> ) newExtendedRequest( jndiRequest.getID(), jndiRequest.getEncodedValue() ); 337 return decorator; 338 } 339 340 341 /** 342 * {@inheritDoc} 343 */ 344 public javax.naming.ldap.ExtendedRequest toJndi( final ExtendedRequest modelRequest ) throws EncoderException 345 { 346 final String oid = modelRequest.getRequestName(); 347 final byte[] value; 348 349 if ( modelRequest instanceof ExtendedRequestDecorator ) 350 { 351 ExtendedRequestDecorator<?> decorator = ( ExtendedRequestDecorator<?> ) modelRequest; 352 value = decorator.getRequestValue(); 353 } 354 else 355 { 356 // have to ask the factory to decorate for us - can't do it ourselves 357 ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( modelRequest 358 .getRequestName() ); 359 ExtendedRequestDecorator<?> decorator = ( ExtendedRequestDecorator<?> ) extendedRequestFactory 360 .decorate( modelRequest ); 361 value = decorator.getRequestValue(); 362 } 363 364 javax.naming.ldap.ExtendedRequest jndiRequest = new javax.naming.ldap.ExtendedRequest() 365 { 366 private static final long serialVersionUID = -4160980385909987475L; 367 368 369 public String getID() 370 { 371 return oid; 372 } 373 374 375 public byte[] getEncodedValue() 376 { 377 return value; 378 } 379 380 381 public javax.naming.ldap.ExtendedResponse createExtendedResponse( String id, byte[] berValue, int offset, 382 int length ) throws NamingException 383 { 384 ExtendedOperationFactory factory = extendedOperationsFactories 385 .get( modelRequest.getRequestName() ); 386 387 try 388 { 389 final ExtendedResponseDecorator<?> resp = ( ExtendedResponseDecorator<?> ) factory 390 .newResponse( berValue ); 391 javax.naming.ldap.ExtendedResponse jndiResponse = new javax.naming.ldap.ExtendedResponse() 392 { 393 private static final long serialVersionUID = -7686354122066100703L; 394 395 396 public String getID() 397 { 398 return oid; 399 } 400 401 402 public byte[] getEncodedValue() 403 { 404 return resp.getResponseValue(); 405 } 406 }; 407 408 return jndiResponse; 409 } 410 catch ( DecoderException e ) 411 { 412 NamingException ne = new NamingException( "Unable to decode encoded response value: " + 413 Strings.dumpBytes( berValue ) ); 414 ne.setRootCause( e ); 415 throw ne; 416 } 417 } 418 }; 419 420 return jndiRequest; 421 } 422 423 424 /** 425 * {@inheritDoc} 426 * @throws DecoderException 427 */ 428 @SuppressWarnings("unchecked") 429 public <E extends ExtendedResponse> E newExtendedResponse( String responseName, int messageId, 430 byte[] serializedResponse ) 431 throws DecoderException 432 { 433 ExtendedResponseDecorator<ExtendedResponse> resp; 434 435 ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( responseName ); 436 437 if ( extendedRequestFactory != null ) 438 { 439 resp = ( ExtendedResponseDecorator<ExtendedResponse> ) extendedRequestFactory 440 .newResponse( serializedResponse ); 441 } 442 else 443 { 444 resp = new ExtendedResponseDecorator<ExtendedResponse>( this, 445 new ExtendedResponseImpl( responseName ) ); 446 resp.setResponseValue( serializedResponse ); 447 resp.setResponseName( responseName ); 448 } 449 450 resp.setMessageId( messageId ); 451 452 return ( E ) resp; 453 } 454 455 456 /** 457 * {@inheritDoc} 458 */ 459 public ExtendedRequest newExtendedRequest( String oid, byte[] value ) 460 { 461 ExtendedRequest req = null; 462 463 ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( oid ); 464 465 if ( extendedRequestFactory != null ) 466 { 467 req = extendedRequestFactory.newRequest( value ); 468 } 469 else 470 { 471 ExtendedRequestDecorator<ExtendedRequest> decorator = 472 new ExtendedRequestDecorator<ExtendedRequest>( this, 473 new ExtendedRequestImpl() ); 474 decorator.setRequestName( oid ); 475 decorator.setRequestValue( value ); 476 req = decorator; 477 } 478 479 return req; 480 } 481 482 483 /** 484 * {@inheritDoc} 485 */ 486 public ExtendedRequestDecorator<?> decorate( ExtendedRequest decoratedMessage ) 487 { 488 ExtendedRequestDecorator<?> req = null; 489 490 ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( decoratedMessage 491 .getRequestName() ); 492 493 if ( extendedRequestFactory != null ) 494 { 495 req = ( ExtendedRequestDecorator<?> ) extendedRequestFactory.decorate( decoratedMessage ); 496 } 497 else 498 { 499 req = new ExtendedRequestDecorator<ExtendedRequest>( this, decoratedMessage ); 500 } 501 502 return req; 503 } 504 505 506 /** 507 * {@inheritDoc} 508 */ 509 public ExtendedResponseDecorator<?> decorate( ExtendedResponse decoratedMessage ) 510 { 511 ExtendedResponseDecorator<?> resp = null; 512 513 ExtendedOperationFactory extendedRequestFactory = extendedOperationsFactories.get( decoratedMessage 514 .getResponseName() ); 515 516 if ( extendedRequestFactory != null ) 517 { 518 resp = ( ExtendedResponseDecorator<?> ) extendedRequestFactory.decorate( decoratedMessage ); 519 } 520 else 521 { 522 resp = new ExtendedResponseDecorator<ExtendedResponse>( this, decoratedMessage ); 523 } 524 525 return resp; 526 } 527 528 529 /** 530 * {@inheritDoc} 531 */ 532 public boolean isExtendedOperationRegistered( String oid ) 533 { 534 return extendedOperationsFactories.containsKey( oid ); 535 } 536}