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