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.decorators; 021 022 023import java.nio.BufferOverflowException; 024import java.nio.ByteBuffer; 025 026import org.apache.directory.api.asn1.EncoderException; 027import org.apache.directory.api.asn1.ber.tlv.BerValue; 028import org.apache.directory.api.asn1.ber.tlv.TLV; 029import org.apache.directory.api.i18n.I18n; 030import org.apache.directory.api.ldap.codec.api.Decorator; 031import org.apache.directory.api.ldap.codec.api.LdapApiService; 032import org.apache.directory.api.ldap.codec.api.LdapEncoder; 033import org.apache.directory.api.ldap.model.message.LdapResult; 034import org.apache.directory.api.ldap.model.message.Referral; 035import org.apache.directory.api.ldap.model.message.ResultCodeEnum; 036import org.apache.directory.api.ldap.model.name.Dn; 037import org.apache.directory.api.util.Strings; 038 039 040/** 041 * A decorator for the LdapResultResponse message 042 * 043 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 044 */ 045public class LdapResultDecorator implements LdapResult, Decorator<LdapResult> 046{ 047 /** The decorated LdapResult */ 048 private final LdapResult decoratedLdapResult; 049 050 /** Temporary storage for message bytes */ 051 private byte[] errorMessageBytes; 052 053 /** Temporary storage of the byte[] representing the matchedDN */ 054 private byte[] matchedDnBytes; 055 056 /** The codec responsible for encoding and decoding this object. */ 057 private LdapApiService codec; 058 059 private static final byte[] DEFAULT_SUCCESS = new byte[] 060 { 0x0A, 0x01, 0x00, 0x04, 0x00, 0x04, 0x00 }; 061 062 063 /** 064 * Makes a LdapResult encodable. 065 * 066 * @param codec The LDAP service instance 067 * @param decoratedLdapResult the decorated LdapResult 068 */ 069 public LdapResultDecorator( LdapApiService codec, LdapResult decoratedLdapResult ) 070 { 071 this.decoratedLdapResult = decoratedLdapResult; 072 this.codec = codec; 073 } 074 075 076 //------------------------------------------------------------------------- 077 // The LdapResult methods 078 //------------------------------------------------------------------------- 079 080 /** 081 * {@inheritDoc} 082 */ 083 @Override 084 public ResultCodeEnum getResultCode() 085 { 086 return decoratedLdapResult.getResultCode(); 087 } 088 089 090 /** 091 * {@inheritDoc} 092 */ 093 @Override 094 public void setResultCode( ResultCodeEnum resultCode ) 095 { 096 decoratedLdapResult.setResultCode( resultCode ); 097 } 098 099 100 /** 101 * {@inheritDoc} 102 */ 103 @Override 104 public Dn getMatchedDn() 105 { 106 return decoratedLdapResult.getMatchedDn(); 107 } 108 109 110 /** 111 * {@inheritDoc} 112 */ 113 @Override 114 public void setMatchedDn( Dn dn ) 115 { 116 decoratedLdapResult.setMatchedDn( dn ); 117 } 118 119 120 /** 121 * {@inheritDoc} 122 */ 123 @Override 124 public String getDiagnosticMessage() 125 { 126 return decoratedLdapResult.getDiagnosticMessage(); 127 } 128 129 130 /** 131 * {@inheritDoc} 132 */ 133 @Override 134 public void setDiagnosticMessage( String diagnosticMessage ) 135 { 136 decoratedLdapResult.setDiagnosticMessage( diagnosticMessage ); 137 } 138 139 140 /** 141 * {@inheritDoc} 142 */ 143 @Override 144 public boolean isReferral() 145 { 146 return decoratedLdapResult.isReferral(); 147 } 148 149 150 /** 151 * {@inheritDoc} 152 */ 153 @Override 154 public Referral getReferral() 155 { 156 return decoratedLdapResult.getReferral(); 157 } 158 159 160 /** 161 * {@inheritDoc} 162 */ 163 @Override 164 public void setReferral( Referral referral ) 165 { 166 decoratedLdapResult.setReferral( referral ); 167 } 168 169 170 /** 171 * {@inheritDoc} 172 */ 173 @Override 174 public String toString() 175 { 176 return decoratedLdapResult.toString(); 177 } 178 179 180 //------------------------------------------------------------------------- 181 // The Decorator methods 182 //------------------------------------------------------------------------- 183 /** 184 * Compute the LdapResult length 185 * <br> 186 * LdapResult : 187 * <pre> 188 * 0x0A 01 resultCode (0..80) 189 * 0x04 L1 matchedDN (L1 = Length(matchedDN)) 190 * 0x04 L2 errorMessage (L2 = Length(errorMessage)) 191 * [0x83 L3] referrals 192 * | 193 * +--> 0x04 L4 referral 194 * +--> 0x04 L5 referral 195 * +--> ... 196 * +--> 0x04 Li referral 197 * +--> ... 198 * +--> 0x04 Ln referral 199 * 200 * L1 = Length(matchedDN) 201 * L2 = Length(errorMessage) 202 * L3 = n*Length(0x04) + sum(Length(L4) .. Length(Ln)) + sum(L4..Ln) 203 * L4..n = Length(0x04) + Length(Li) + Li 204 * Length(LdapResult) = Length(0x0x0A) + 205 * Length(0x01) + 1 + Length(0x04) + Length(L1) + L1 + Length(0x04) + 206 * Length(L2) + L2 + Length(0x83) + Length(L3) + L3 207 * </pre> 208 */ 209 @Override 210 public int computeLength() 211 { 212 if ( decoratedLdapResult.isDefaultSuccess() ) 213 { 214 // The length of a default success PDU : 0xA0 0x01 0x00 0x04 0x00 0x04 0x00 215 return DEFAULT_SUCCESS.length; 216 } 217 218 int ldapResultLength; 219 220 // The result code 221 ldapResultLength = 1 + 1 + BerValue.getNbBytes( getResultCode().getValue() ); 222 223 // The matchedDN length 224 if ( getMatchedDn() == null ) 225 { 226 ldapResultLength += 1 + 1; 227 } 228 else 229 { 230 matchedDnBytes = Strings.getBytesUtf8Ascii( Strings.trimLeft( getMatchedDn().getName() ) ); 231 ldapResultLength += 1 + TLV.getNbBytes( matchedDnBytes.length ) + matchedDnBytes.length; 232 } 233 234 // The errorMessage length 235 errorMessageBytes = Strings.getBytesUtf8Ascii( getDiagnosticMessage() ); 236 ldapResultLength += 1 + TLV.getNbBytes( errorMessageBytes.length ) + errorMessageBytes.length; 237 238 int referralLength = LdapEncoder.computeReferralLength( getReferral() ); 239 240 if ( referralLength != 0 ) 241 { 242 // The referrals 243 ldapResultLength += 1 + TLV.getNbBytes( referralLength ) + referralLength; 244 } 245 246 return ldapResultLength; 247 } 248 249 250 /** 251 * Encode the LdapResult message to a PDU. 252 * 253 * @param buffer The buffer where to put the PDU 254 * @return The PDU. 255 */ 256 @Override 257 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 258 { 259 if ( buffer == null ) 260 { 261 throw new EncoderException( I18n.err( I18n.ERR_04023 ) ); 262 } 263 264 if ( decoratedLdapResult.isDefaultSuccess() ) 265 { 266 // The length of a default success PDU : 0xA0 0x01 0x00 0x04 0x00 0x04 0x00 267 buffer.put( DEFAULT_SUCCESS ); 268 269 return buffer; 270 } 271 272 try 273 { 274 // The result code 275 BerValue.encodeEnumerated( buffer, getResultCode().getValue() ); 276 } 277 catch ( BufferOverflowException boe ) 278 { 279 throw new EncoderException( I18n.err( I18n.ERR_04005 ), boe ); 280 } 281 282 // The matchedDN 283 BerValue.encode( buffer, matchedDnBytes ); 284 285 // The error message 286 BerValue.encode( buffer, errorMessageBytes ); 287 288 // The referrals, if any 289 Referral referral = getReferral(); 290 291 if ( referral != null ) 292 { 293 LdapEncoder.encodeReferral( buffer, referral ); 294 } 295 296 return buffer; 297 } 298 299 300 /** 301 * {@inheritDoc} 302 */ 303 @Override 304 public LdapResult getDecorated() 305 { 306 return decoratedLdapResult; 307 } 308 309 310 /** 311 * {@inheritDoc} 312 */ 313 @Override 314 public LdapApiService getCodecService() 315 { 316 return codec; 317 } 318 319 320 /** 321 * {@inheritDoc} 322 */ 323 @Override 324 public boolean isDefaultSuccess() 325 { 326 return decoratedLdapResult.isDefaultSuccess(); 327 } 328}