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 */ 020 package org.apache.directory.shared.ldap.codec.search.controls.entryChange; 021 022 023 import org.apache.directory.shared.asn1.ber.IAsn1Container; 024 import org.apache.directory.shared.asn1.ber.grammar.AbstractGrammar; 025 import org.apache.directory.shared.asn1.ber.grammar.GrammarAction; 026 import org.apache.directory.shared.asn1.ber.grammar.GrammarTransition; 027 import org.apache.directory.shared.asn1.ber.grammar.IGrammar; 028 import org.apache.directory.shared.asn1.ber.tlv.UniversalTag; 029 import org.apache.directory.shared.asn1.ber.tlv.Value; 030 import org.apache.directory.shared.asn1.codec.DecoderException; 031 import org.apache.directory.shared.asn1.util.IntegerDecoder; 032 import org.apache.directory.shared.asn1.util.IntegerDecoderException; 033 import org.apache.directory.shared.asn1.util.LongDecoder; 034 import org.apache.directory.shared.asn1.util.LongDecoderException; 035 import org.apache.directory.shared.i18n.I18n; 036 import org.apache.directory.shared.ldap.codec.search.controls.ChangeType; 037 import org.apache.directory.shared.ldap.exception.LdapInvalidDnException; 038 import org.apache.directory.shared.ldap.name.DN; 039 import org.apache.directory.shared.ldap.util.StringTools; 040 import org.slf4j.Logger; 041 import org.slf4j.LoggerFactory; 042 043 044 /** 045 * This class implements the EntryChangeControl. All the actions are declared in 046 * this class. As it is a singleton, these declaration are only done once. 047 * 048 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 049 * @version $Rev: 923473 $, $Date: 2010-03-15 23:25:03 +0100 (Mon, 15 Mar 2010) $, 050 */ 051 public class EntryChangeControlGrammar extends AbstractGrammar 052 { 053 /** The logger */ 054 static final Logger log = LoggerFactory.getLogger( EntryChangeControlGrammar.class ); 055 056 /** Speedup for logs */ 057 static final boolean IS_DEBUG = log.isDebugEnabled(); 058 059 /** The instance of grammar. EntryChangeControlGrammar is a singleton */ 060 private static IGrammar instance = new EntryChangeControlGrammar(); 061 062 063 /** 064 * Creates a new EntryChangeControlGrammar object. 065 */ 066 private EntryChangeControlGrammar() 067 { 068 name = EntryChangeControlGrammar.class.getName(); 069 statesEnum = EntryChangeControlStatesEnum.getInstance(); 070 071 // Create the transitions table 072 super.transitions = new GrammarTransition[EntryChangeControlStatesEnum.LAST_EC_STATE][256]; 073 074 // ============================================================================================ 075 // Transition from start state to Entry Change sequence 076 // ============================================================================================ 077 // EntryChangeNotification ::= SEQUENCE { 078 // ... 079 // 080 // Initialization of the structure 081 super.transitions[EntryChangeControlStatesEnum.START_STATE][UniversalTag.SEQUENCE_TAG] = 082 new GrammarTransition( EntryChangeControlStatesEnum.START_STATE, 083 EntryChangeControlStatesEnum.EC_SEQUENCE_STATE, 084 UniversalTag.SEQUENCE_TAG, null ); 085 086 // ============================================================================================ 087 // transition from Entry Change sequence to Change Type 088 // ============================================================================================ 089 // EntryChangeNotification ::= SEQUENCE { 090 // changeType ENUMERATED { 091 // ... 092 // 093 // Evaluates the changeType 094 super.transitions[EntryChangeControlStatesEnum.EC_SEQUENCE_STATE][UniversalTag.ENUMERATED_TAG] = 095 new GrammarTransition( EntryChangeControlStatesEnum.EC_SEQUENCE_STATE, 096 EntryChangeControlStatesEnum.CHANGE_TYPE_STATE, 097 UniversalTag.ENUMERATED_TAG, 098 new GrammarAction( "Set EntryChangeControl changeType" ) 099 { 100 public void action( IAsn1Container container ) throws DecoderException 101 { 102 EntryChangeControlContainer entryChangeContainer = ( EntryChangeControlContainer ) container; 103 Value value = entryChangeContainer.getCurrentTLV().getValue(); 104 105 try 106 { 107 int change = IntegerDecoder.parse( value, 1, 8 ); 108 109 switch ( change ) 110 { 111 case ChangeType.ADD_VALUE: 112 case ChangeType.DELETE_VALUE: 113 case ChangeType.MODDN_VALUE: 114 case ChangeType.MODIFY_VALUE: 115 ChangeType changeType = ChangeType.getChangeType( change ); 116 117 if ( IS_DEBUG ) 118 { 119 log.debug( "changeType = " + changeType ); 120 } 121 122 entryChangeContainer.getEntryChangeControl().setChangeType( changeType ); 123 break; 124 125 default: 126 String msg = I18n.err( I18n.ERR_04044 ); 127 log.error( msg ); 128 throw new DecoderException( msg ); 129 } 130 131 // We can have an END transition 132 entryChangeContainer.grammarEndAllowed( true ); 133 } 134 catch ( IntegerDecoderException e ) 135 { 136 String msg = I18n.err( I18n.ERR_04044 ); 137 log.error( msg, e ); 138 throw new DecoderException( msg ); 139 } 140 } 141 } ); 142 143 // ============================================================================================ 144 // Transition from Change Type to Previous DN 145 // ============================================================================================ 146 // EntryChangeNotification ::= SEQUENCE { 147 // ... 148 // previousDN LDAPDN OPTIONAL, 149 // ... 150 // 151 // Set the previousDN into the structure. We first check that it's a 152 // valid DN 153 super.transitions[EntryChangeControlStatesEnum.CHANGE_TYPE_STATE][UniversalTag.OCTET_STRING_TAG] = 154 new GrammarTransition( EntryChangeControlStatesEnum.CHANGE_TYPE_STATE, 155 EntryChangeControlStatesEnum.PREVIOUS_DN_STATE, 156 UniversalTag.OCTET_STRING_TAG, 157 new GrammarAction( "Set EntryChangeControl previousDN" ) 158 { 159 public void action( IAsn1Container container ) throws DecoderException 160 { 161 EntryChangeControlContainer entryChangeContainer = ( EntryChangeControlContainer ) container; 162 163 ChangeType changeType = entryChangeContainer.getEntryChangeControl().getChangeType(); 164 165 if ( changeType != ChangeType.MODDN ) 166 { 167 log.error( I18n.err( I18n.ERR_04045 ) ); 168 throw new DecoderException( I18n.err( I18n.ERR_04046 )); 169 } 170 else 171 { 172 Value value = entryChangeContainer.getCurrentTLV().getValue(); 173 DN previousDn = null; 174 175 try 176 { 177 previousDn = new DN( StringTools.utf8ToString( value.getData() ) ); 178 } 179 catch ( LdapInvalidDnException ine ) 180 { 181 log.error( I18n.err( I18n.ERR_04047, StringTools.dumpBytes( value.getData() ) ) ); 182 throw new DecoderException( I18n.err( I18n.ERR_04048 ) ); 183 } 184 185 if ( IS_DEBUG ) 186 { 187 log.debug( "previousDN = " + previousDn ); 188 } 189 190 entryChangeContainer.getEntryChangeControl().setPreviousDn( previousDn ); 191 192 // We can have an END transition 193 entryChangeContainer.grammarEndAllowed( true ); 194 } 195 } 196 } ); 197 198 // Change Number action 199 GrammarAction setChangeNumberAction = new GrammarAction( "Set EntryChangeControl changeNumber" ) 200 { 201 public void action( IAsn1Container container ) throws DecoderException 202 { 203 EntryChangeControlContainer entryChangeContainer = ( EntryChangeControlContainer ) container; 204 Value value = entryChangeContainer.getCurrentTLV().getValue(); 205 206 try 207 { 208 long changeNumber = LongDecoder.parse( value ); 209 210 if ( IS_DEBUG ) 211 { 212 log.debug( "changeNumber = " + changeNumber ); 213 } 214 215 entryChangeContainer.getEntryChangeControl().setChangeNumber( changeNumber ); 216 217 // We can have an END transition 218 entryChangeContainer.grammarEndAllowed( true ); 219 } 220 catch ( LongDecoderException e ) 221 { 222 String msg = I18n.err( I18n.ERR_04049 ); 223 log.error( msg, e ); 224 throw new DecoderException( msg ); 225 } 226 } 227 }; 228 229 // ============================================================================================ 230 // Transition from Previous DN to Change Number 231 // ============================================================================================ 232 // EntryChangeNotification ::= SEQUENCE { 233 // ... 234 // changeNumber INTEGER OPTIONAL 235 // } 236 // 237 // Set the changeNumber into the structure 238 super.transitions[EntryChangeControlStatesEnum.PREVIOUS_DN_STATE][UniversalTag.INTEGER_TAG] = 239 new GrammarTransition( EntryChangeControlStatesEnum.PREVIOUS_DN_STATE, 240 EntryChangeControlStatesEnum.CHANGE_NUMBER_STATE, 241 UniversalTag.INTEGER_TAG, 242 setChangeNumberAction ); 243 244 // ============================================================================================ 245 // Transition from Previous DN to Change Number 246 // ============================================================================================ 247 // EntryChangeNotification ::= SEQUENCE { 248 // ... 249 // changeNumber INTEGER OPTIONAL 250 // } 251 // 252 // Set the changeNumber into the structure 253 super.transitions[EntryChangeControlStatesEnum.CHANGE_TYPE_STATE][UniversalTag.INTEGER_TAG] = 254 new GrammarTransition( EntryChangeControlStatesEnum.CHANGE_TYPE_STATE, 255 EntryChangeControlStatesEnum.CHANGE_NUMBER_STATE, 256 UniversalTag.INTEGER_TAG, 257 setChangeNumberAction ); 258 } 259 260 261 /** 262 * This class is a singleton. 263 * 264 * @return An instance on this grammar 265 */ 266 public static IGrammar getInstance() 267 { 268 return instance; 269 } 270 }