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.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 /** Speedup for logs */ 055 static final boolean IS_DEBUG = LOG.isDebugEnabled(); 056 057 /** The instance of grammar. EntryChangeGrammar is a singleton */ 058 private static Grammar<?> instance = new EntryChangeGrammar(); 059 060 061 /** 062 * Creates a new EntryChangeGrammar object. 063 */ 064 @SuppressWarnings("unchecked") 065 private EntryChangeGrammar() 066 { 067 setName( EntryChangeGrammar.class.getName() ); 068 069 // Create the transitions table 070 super.transitions = new GrammarTransition[EntryChangeStates.LAST_EC_STATE.ordinal()][256]; 071 072 // ============================================================================================ 073 // Transition from start state to Entry Change sequence 074 // ============================================================================================ 075 // EntryChangeNotification ::= SEQUENCE { 076 // ... 077 // 078 // Initialization of the structure 079 super.transitions[EntryChangeStates.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 080 new GrammarTransition<EntryChangeContainer>( EntryChangeStates.START_STATE, 081 EntryChangeStates.EC_SEQUENCE_STATE, 082 UniversalTag.SEQUENCE.getValue(), null ); 083 084 // ============================================================================================ 085 // transition from Entry Change sequence to Change Type 086 // ============================================================================================ 087 // EntryChangeNotification ::= SEQUENCE { 088 // changeType ENUMERATED { 089 // ... 090 // 091 // Evaluates the changeType 092 super.transitions[EntryChangeStates.EC_SEQUENCE_STATE.ordinal()][UniversalTag.ENUMERATED.getValue()] = 093 new GrammarTransition<EntryChangeContainer>( EntryChangeStates.EC_SEQUENCE_STATE, 094 EntryChangeStates.CHANGE_TYPE_STATE, 095 UniversalTag.ENUMERATED.getValue(), 096 new GrammarAction<EntryChangeContainer>( "Set EntryChangeControl changeType" ) 097 { 098 public void action( EntryChangeContainer container ) throws DecoderException 099 { 100 BerValue value = container.getCurrentTLV().getValue(); 101 102 try 103 { 104 int change = IntegerDecoder.parse( value, 1, 8 ); 105 106 switch ( ChangeType.getChangeType( change ) ) 107 { 108 case ADD: 109 case DELETE: 110 case MODDN: 111 case MODIFY: 112 ChangeType changeType = ChangeType.getChangeType( change ); 113 114 if ( IS_DEBUG ) 115 { 116 LOG.debug( "changeType = " + changeType ); 117 } 118 119 container.getEntryChangeDecorator().setChangeType( changeType ); 120 break; 121 122 default: 123 String msg = I18n.err( I18n.ERR_04044 ); 124 LOG.error( msg ); 125 throw new DecoderException( msg ); 126 } 127 128 // We can have an END transition 129 container.setGrammarEndAllowed( true ); 130 } 131 catch ( IntegerDecoderException e ) 132 { 133 String msg = I18n.err( I18n.ERR_04044 ); 134 LOG.error( msg, e ); 135 throw new DecoderException( msg ); 136 } 137 catch ( IllegalArgumentException e ) 138 { 139 throw new DecoderException( e.getLocalizedMessage() ); 140 } 141 } 142 } ); 143 144 // ============================================================================================ 145 // Transition from Change Type to Previous Dn 146 // ============================================================================================ 147 // EntryChangeNotification ::= SEQUENCE { 148 // ... 149 // previousDN LDAPDN OPTIONAL, 150 // ... 151 // 152 // Set the previousDN into the structure. We first check that it's a 153 // valid Dn 154 super.transitions[EntryChangeStates.CHANGE_TYPE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = 155 new GrammarTransition<EntryChangeContainer>( EntryChangeStates.CHANGE_TYPE_STATE, 156 EntryChangeStates.PREVIOUS_DN_STATE, 157 UniversalTag.OCTET_STRING.getValue(), 158 new GrammarAction<EntryChangeContainer>( "Set EntryChangeControl previousDN" ) 159 { 160 public void action( EntryChangeContainer container ) throws DecoderException 161 { 162 ChangeType changeType = container.getEntryChangeDecorator().getChangeType(); 163 164 if ( changeType != ChangeType.MODDN ) 165 { 166 LOG.error( I18n.err( I18n.ERR_04045 ) ); 167 throw new DecoderException( I18n.err( I18n.ERR_04046 ) ); 168 } 169 else 170 { 171 BerValue value = container.getCurrentTLV().getValue(); 172 Dn previousDn; 173 174 try 175 { 176 previousDn = new Dn( Strings.utf8ToString( value.getData() ) ); 177 } 178 catch ( LdapInvalidDnException ine ) 179 { 180 LOG.error( I18n.err( I18n.ERR_04047, Strings.dumpBytes( value.getData() ) ) ); 181 throw new DecoderException( I18n.err( I18n.ERR_04048 ) ); 182 } 183 184 if ( IS_DEBUG ) 185 { 186 LOG.debug( "previousDN = " + previousDn ); 187 } 188 189 container.getEntryChangeDecorator().setPreviousDn( previousDn ); 190 191 // We can have an END transition 192 container.setGrammarEndAllowed( true ); 193 } 194 } 195 } ); 196 197 // Change Number action 198 GrammarAction<EntryChangeContainer> setChangeNumberAction = new GrammarAction<EntryChangeContainer>( 199 "Set EntryChangeControl changeNumber" ) 200 { 201 public void action( EntryChangeContainer container ) throws DecoderException 202 { 203 BerValue value = container.getCurrentTLV().getValue(); 204 205 try 206 { 207 long changeNumber = LongDecoder.parse( value ); 208 209 if ( IS_DEBUG ) 210 { 211 LOG.debug( "changeNumber = " + changeNumber ); 212 } 213 214 container.getEntryChangeDecorator().setChangeNumber( changeNumber ); 215 216 // We can have an END transition 217 container.setGrammarEndAllowed( true ); 218 } 219 catch ( LongDecoderException e ) 220 { 221 String msg = I18n.err( I18n.ERR_04049 ); 222 LOG.error( msg, e ); 223 throw new DecoderException( msg ); 224 } 225 } 226 }; 227 228 // ============================================================================================ 229 // Transition from Previous Dn to Change Number 230 // ============================================================================================ 231 // EntryChangeNotification ::= SEQUENCE { 232 // ... 233 // changeNumber INTEGER OPTIONAL 234 // } 235 // 236 // Set the changeNumber into the structure 237 super.transitions[EntryChangeStates.PREVIOUS_DN_STATE.ordinal()][UniversalTag.INTEGER.getValue()] = 238 new GrammarTransition<EntryChangeContainer>( EntryChangeStates.PREVIOUS_DN_STATE, 239 EntryChangeStates.CHANGE_NUMBER_STATE, 240 UniversalTag.INTEGER.getValue(), 241 setChangeNumberAction ); 242 243 // ============================================================================================ 244 // Transition from Previous Dn to Change Number 245 // ============================================================================================ 246 // EntryChangeNotification ::= SEQUENCE { 247 // ... 248 // changeNumber INTEGER OPTIONAL 249 // } 250 // 251 // Set the changeNumber into the structure 252 super.transitions[EntryChangeStates.CHANGE_TYPE_STATE.ordinal()][UniversalTag.INTEGER.getValue()] = 253 new GrammarTransition<EntryChangeContainer>( EntryChangeStates.CHANGE_TYPE_STATE, 254 EntryChangeStates.CHANGE_NUMBER_STATE, 255 UniversalTag.INTEGER.getValue(), 256 setChangeNumberAction ); 257 } 258 259 260 /** 261 * This class is a singleton. 262 * 263 * @return An instance on this grammar 264 */ 265 public static Grammar<?> getInstance() 266 { 267 return instance; 268 } 269}