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.controls.replication.syncInfoValue;
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.grammar.IStates;
029    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
030    import org.apache.directory.shared.asn1.ber.tlv.Value;
031    import org.apache.directory.shared.asn1.codec.DecoderException;
032    import org.apache.directory.shared.asn1.util.BooleanDecoder;
033    import org.apache.directory.shared.asn1.util.BooleanDecoderException;
034    import org.apache.directory.shared.i18n.I18n;
035    import org.apache.directory.shared.ldap.message.control.replication.SynchronizationInfoEnum;
036    import org.apache.directory.shared.ldap.util.StringTools;
037    import org.slf4j.Logger;
038    import org.slf4j.LoggerFactory;
039    
040    
041    /**
042     * This class implements the SyncInfoValueControl. All the actions are declared in
043     * this class. As it is a singleton, these declaration are only done once.
044     * 
045     * The decoded grammar is the following :
046     * 
047     * syncInfoValue ::= CHOICE {
048     *     newcookie      [0] syncCookie,
049     *     refreshDelete  [1] SEQUENCE {
050     *         cookie         syncCookie OPTIONAL,
051     *         refreshDone    BOOLEAN DEFAULT TRUE
052     *     },
053     *     refreshPresent [2] SEQUENCE {
054     *         cookie         syncCookie OPTIONAL,
055     *         refreshDone    BOOLEAN DEFAULT TRUE
056     *     },
057     *     syncIdSet      [3] SEQUENCE {
058     *         cookie         syncCookie OPTIONAL,
059     *         refreshDeletes BOOLEAN DEFAULT FALSE,
060     *         syncUUIDs      SET OF syncUUID
061     *     }
062     * }
063     * 
064     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
065     * @version $Rev: 741888 $, $Date: 2009-02-07 13:57:03 +0100 (Sat, 07 Feb 2009) $, 
066     */
067    public class SyncInfoValueControlGrammar extends AbstractGrammar
068    {
069        /** The logger */
070        static final Logger LOG = LoggerFactory.getLogger( SyncInfoValueControlGrammar.class );
071    
072        /** Speedup for logs */
073        static final boolean IS_DEBUG = LOG.isDebugEnabled();
074    
075        /** The instance of grammar. SyncInfoValueControlGrammar is a singleton */
076        private static IGrammar instance = new SyncInfoValueControlGrammar();
077    
078    
079        /**
080         * Creates a new SyncInfoValueControlGrammar object.
081         */
082        private SyncInfoValueControlGrammar()
083        {
084            name = SyncInfoValueControlGrammar.class.getName();
085            statesEnum = SyncInfoValueControlStatesEnum.getInstance();
086    
087            // Create the transitions table
088            super.transitions = new GrammarTransition[SyncInfoValueControlStatesEnum.LAST_SYNC_INFO_VALUE_STATE][256];
089    
090            /** 
091             * Transition from initial state to SyncInfoValue newCookie choice
092             * SyncInfoValue ::= CHOICE {
093             *     newCookie [0] syncCookie,
094             *     ...
095             *     
096             * Initialize the syncInfoValue object
097             */
098            super.transitions[IStates.INIT_GRAMMAR_STATE][SyncInfoValueTags.NEW_COOKIE_TAG.getValue()] = 
099                new GrammarTransition( IStates.INIT_GRAMMAR_STATE, 
100                                        SyncInfoValueControlStatesEnum.NEW_COOKIE_STATE, 
101                                        SyncInfoValueTags.NEW_COOKIE_TAG.getValue(), 
102                    new GrammarAction( "NewCookie choice for SyncInfoValueControl" )
103                {
104                    public void action( IAsn1Container container )
105                    {
106                        SyncInfoValueControlContainer syncInfoValueContainer = 
107                            ( SyncInfoValueControlContainer ) container;
108                        SyncInfoValueControl control = 
109                            new SyncInfoValueControl( SynchronizationInfoEnum.NEW_COOKIE);
110                        
111                        Value value = syncInfoValueContainer.getCurrentTLV().getValue();
112    
113                        byte[] newCookie = value.getData();
114    
115                        if ( IS_DEBUG )
116                        {
117                            LOG.debug( "newcookie = " + StringTools.dumpBytes( newCookie ) );
118                        }
119    
120                        control.setCookie( newCookie );
121    
122                        // We can have an END transition
123                        syncInfoValueContainer.grammarEndAllowed( true );
124                        
125                        syncInfoValueContainer.setSyncInfoValueControl( control );
126                    }
127                } );
128    
129    
130            /** 
131             * Transition from initial state to SyncInfoValue refreshDelete choice
132             * SyncInfoValue ::= CHOICE {
133             *     ...
134             *     refreshDelete [1] SEQUENCE {
135             *     ...
136             *     
137             * Initialize the syncInfoValue object
138             */
139            super.transitions[IStates.INIT_GRAMMAR_STATE][SyncInfoValueTags.REFRESH_DELETE_TAG.getValue()] = 
140                new GrammarTransition( IStates.INIT_GRAMMAR_STATE, 
141                                        SyncInfoValueControlStatesEnum.REFRESH_DELETE_STATE, 
142                                        SyncInfoValueTags.REFRESH_DELETE_TAG.getValue(), 
143                    new GrammarAction( "RefreshDelete choice for SyncInfoValueControl" )
144                {
145                    public void action( IAsn1Container container )
146                    {
147                        SyncInfoValueControlContainer syncInfoValueContainer = 
148                            ( SyncInfoValueControlContainer ) container;
149                        SyncInfoValueControl control = 
150                            new SyncInfoValueControl( SynchronizationInfoEnum.REFRESH_DELETE);
151                        
152                        syncInfoValueContainer.setSyncInfoValueControl( control );
153    
154                        // We can have an END transition
155                        syncInfoValueContainer.grammarEndAllowed( true );
156                    }
157                } );
158    
159    
160            /** 
161             * Transition from refreshDelete state to cookie
162             *     refreshDelete [1] SEQUENCE {
163             *         cookie syncCookie OPTIONAL,
164             *     ...
165             *     
166             * Load the cookie object
167             */
168            super.transitions[SyncInfoValueControlStatesEnum.REFRESH_DELETE_STATE][UniversalTag.OCTET_STRING_TAG] = 
169                new GrammarTransition( SyncInfoValueControlStatesEnum.REFRESH_DELETE_STATE, 
170                                        SyncInfoValueControlStatesEnum.REFRESH_DELETE_COOKIE_STATE, 
171                                        UniversalTag.OCTET_STRING_TAG, 
172                    new GrammarAction( "RefreshDelete cookie" )
173                {
174                    public void action( IAsn1Container container )
175                    {
176                        SyncInfoValueControlContainer syncInfoValueContainer = 
177                            ( SyncInfoValueControlContainer ) container;
178                        SyncInfoValueControl control = syncInfoValueContainer.getSyncInfoValueControl();
179                        
180                        Value value = syncInfoValueContainer.getCurrentTLV().getValue();
181    
182                        byte[] cookie = value.getData();
183    
184                        if ( IS_DEBUG )
185                        {
186                            LOG.debug( "cookie = " + StringTools.dumpBytes( cookie ) );
187                        }
188    
189                        syncInfoValueContainer.getSyncInfoValueControl().setCookie( cookie );
190                        syncInfoValueContainer.setSyncInfoValueControl( control );
191    
192                        // We can have an END transition
193                        syncInfoValueContainer.grammarEndAllowed( true );
194                    }
195                } );
196    
197    
198            /** 
199             * Transition from refreshDelete cookie state to refreshDone
200             *     refreshDelete [1] SEQUENCE {
201             *         ....
202             *         refreshDone BOOLEAN DEFAULT TRUE
203             *     }
204             *     
205             * Load the refreshDone flag
206             */
207            super.transitions[SyncInfoValueControlStatesEnum.REFRESH_DELETE_COOKIE_STATE][UniversalTag.BOOLEAN_TAG] = 
208                new GrammarTransition( SyncInfoValueControlStatesEnum.REFRESH_DELETE_COOKIE_STATE, 
209                                        SyncInfoValueControlStatesEnum.LAST_SYNC_INFO_VALUE_STATE, 
210                                        UniversalTag.BOOLEAN_TAG, 
211                    new GrammarAction( "RefreshDelete refreshDone flag" )
212                {
213                    public void action( IAsn1Container container ) throws DecoderException
214                    {
215                        SyncInfoValueControlContainer syncInfoValueContainer = 
216                            ( SyncInfoValueControlContainer ) container;
217                        SyncInfoValueControl control = syncInfoValueContainer.getSyncInfoValueControl();
218                        
219                        Value value = syncInfoValueContainer.getCurrentTLV().getValue();
220    
221                        try
222                        {
223                            boolean refreshDone = BooleanDecoder.parse( value );
224    
225                            if ( IS_DEBUG )
226                            {
227                                LOG.debug( "refreshDone = {}", refreshDone );
228                            }
229    
230                            control.setRefreshDone( refreshDone );
231    
232                            syncInfoValueContainer.setSyncInfoValueControl( control );
233    
234                            // the END transition for grammar
235                            syncInfoValueContainer.grammarEndAllowed( true );
236                        }
237                        catch ( BooleanDecoderException be )
238                        {
239                            String msg = I18n.err( I18n.ERR_04025 );
240                            LOG.error( msg, be );
241                            throw new DecoderException( msg );
242                        }
243    
244    
245                        // We can have an END transition
246                        syncInfoValueContainer.grammarEndAllowed( true );
247                    }
248                } );
249    
250    
251            /** 
252             * Transition from refreshDelete choice state to refreshDone
253             *     refreshDelete [1] SEQUENCE {
254             *         ....
255             *         refreshDone BOOLEAN DEFAULT TRUE
256             *     }
257             *     
258             * Load the refreshDone flag
259             */
260            super.transitions[SyncInfoValueControlStatesEnum.REFRESH_DELETE_STATE][UniversalTag.BOOLEAN_TAG] = 
261                new GrammarTransition( SyncInfoValueControlStatesEnum.REFRESH_DELETE_STATE, 
262                                        SyncInfoValueControlStatesEnum.LAST_SYNC_INFO_VALUE_STATE, 
263                                        UniversalTag.BOOLEAN_TAG, 
264                    new GrammarAction( "RefreshDelete refreshDone flag" )
265                {
266                    public void action( IAsn1Container container ) throws DecoderException
267                    {
268                        SyncInfoValueControlContainer syncInfoValueContainer = 
269                            ( SyncInfoValueControlContainer ) container;
270                        SyncInfoValueControl control = syncInfoValueContainer.getSyncInfoValueControl();
271                        
272                        Value value = syncInfoValueContainer.getCurrentTLV().getValue();
273    
274                        try
275                        {
276                            boolean refreshDone = BooleanDecoder.parse( value );
277    
278                            if ( IS_DEBUG )
279                            {
280                                LOG.debug( "refreshDone = {}", refreshDone );
281                            }
282    
283                            control.setRefreshDone( refreshDone );
284    
285                            syncInfoValueContainer.setSyncInfoValueControl( control );
286    
287                            // the END transition for grammar
288                            syncInfoValueContainer.grammarEndAllowed( true );
289                        }
290                        catch ( BooleanDecoderException be )
291                        {
292                            String msg = I18n.err( I18n.ERR_04025 );
293                            LOG.error( msg, be );
294                            throw new DecoderException( msg );
295                        }
296    
297    
298                        // We can have an END transition
299                        syncInfoValueContainer.grammarEndAllowed( true );
300                    }
301                } );
302            
303            
304            /** 
305             * Transition from initial state to SyncInfoValue refreshPresent choice
306             * SyncInfoValue ::= CHOICE {
307             *     ...
308             *     refreshPresent [2] SEQUENCE {
309             *     ...
310             *     
311             * Initialize the syncInfoValue object
312             */
313            super.transitions[IStates.INIT_GRAMMAR_STATE][SyncInfoValueTags.REFRESH_PRESENT_TAG.getValue()] = 
314                new GrammarTransition( IStates.INIT_GRAMMAR_STATE, 
315                                        SyncInfoValueControlStatesEnum.REFRESH_PRESENT_STATE, 
316                                        SyncInfoValueTags.REFRESH_PRESENT_TAG.getValue(), 
317                    new GrammarAction( "RefreshDelete choice for SyncInfoValueControl" )
318                {
319                    public void action( IAsn1Container container )
320                    {
321                        SyncInfoValueControlContainer syncInfoValueContainer = 
322                            ( SyncInfoValueControlContainer ) container;
323                        SyncInfoValueControl control = 
324                            new SyncInfoValueControl( SynchronizationInfoEnum.REFRESH_PRESENT);
325                        
326                        syncInfoValueContainer.setSyncInfoValueControl( control );
327    
328                        // We can have an END transition
329                        syncInfoValueContainer.grammarEndAllowed( true );
330                    }
331                } );
332    
333        
334            /** 
335             * Transition from refreshPresent state to cookie
336             *     refreshPresent [2] SEQUENCE {
337             *         cookie syncCookie OPTIONAL,
338             *     ...
339             *     
340             * Load the cookie object
341             */
342            super.transitions[SyncInfoValueControlStatesEnum.REFRESH_PRESENT_STATE][UniversalTag.OCTET_STRING_TAG] = 
343                new GrammarTransition( SyncInfoValueControlStatesEnum.REFRESH_PRESENT_STATE, 
344                                        SyncInfoValueControlStatesEnum.REFRESH_PRESENT_COOKIE_STATE, 
345                                        UniversalTag.OCTET_STRING_TAG, 
346                    new GrammarAction( "RefreshPresent cookie" )
347                {
348                    public void action( IAsn1Container container )
349                    {
350                        SyncInfoValueControlContainer syncInfoValueContainer = 
351                            ( SyncInfoValueControlContainer ) container;
352                        SyncInfoValueControl control = syncInfoValueContainer.getSyncInfoValueControl();
353                        
354                        Value value = syncInfoValueContainer.getCurrentTLV().getValue();
355    
356                        byte[] cookie = value.getData();
357    
358                        if ( IS_DEBUG )
359                        {
360                            LOG.debug( "cookie = " + StringTools.dumpBytes( cookie ) );
361                        }
362    
363                        syncInfoValueContainer.getSyncInfoValueControl().setCookie( cookie );
364                        syncInfoValueContainer.setSyncInfoValueControl( control );
365    
366                        // We can have an END transition
367                        syncInfoValueContainer.grammarEndAllowed( true );
368                    }
369                } );
370            
371            
372    
373    
374            /** 
375             * Transition from refreshPresent cookie state to refreshDone
376             *     refreshPresent [2] SEQUENCE {
377             *         ....
378             *         refreshDone BOOLEAN DEFAULT TRUE
379             *     }
380             *     
381             * Load the refreshDone flag
382             */
383            super.transitions[SyncInfoValueControlStatesEnum.REFRESH_PRESENT_COOKIE_STATE][UniversalTag.BOOLEAN_TAG] = 
384                new GrammarTransition( SyncInfoValueControlStatesEnum.REFRESH_PRESENT_COOKIE_STATE, 
385                                        SyncInfoValueControlStatesEnum.LAST_SYNC_INFO_VALUE_STATE, 
386                                        UniversalTag.BOOLEAN_TAG, 
387                    new GrammarAction( "RefreshPresent refreshDone flag" )
388                {
389                    public void action( IAsn1Container container ) throws DecoderException
390                    {
391                        SyncInfoValueControlContainer syncInfoValueContainer = 
392                            ( SyncInfoValueControlContainer ) container;
393                        SyncInfoValueControl control = syncInfoValueContainer.getSyncInfoValueControl();
394                        
395                        Value value = syncInfoValueContainer.getCurrentTLV().getValue();
396    
397                        try
398                        {
399                            boolean refreshDone = BooleanDecoder.parse( value );
400    
401                            if ( IS_DEBUG )
402                            {
403                                LOG.debug( "refreshDone = {}", refreshDone );
404                            }
405    
406                            control.setRefreshDone( refreshDone );
407    
408                            syncInfoValueContainer.setSyncInfoValueControl( control );
409    
410                            // the END transition for grammar
411                            syncInfoValueContainer.grammarEndAllowed( true );
412                        }
413                        catch ( BooleanDecoderException be )
414                        {
415                            String msg = I18n.err( I18n.ERR_04025 );
416                            LOG.error( msg, be );
417                            throw new DecoderException( msg );
418                        }
419    
420    
421                        // We can have an END transition
422                        syncInfoValueContainer.grammarEndAllowed( true );
423                    }
424                } );
425    
426    
427            /** 
428             * Transition from refreshPresent choice state to refreshDone
429             *     refreshPresent [1] SEQUENCE {
430             *         ....
431             *         refreshDone BOOLEAN DEFAULT TRUE
432             *     }
433             *     
434             * Load the refreshDone flag
435             */
436            super.transitions[SyncInfoValueControlStatesEnum.REFRESH_PRESENT_STATE][UniversalTag.BOOLEAN_TAG] = 
437                new GrammarTransition( SyncInfoValueControlStatesEnum.REFRESH_PRESENT_STATE, 
438                                        SyncInfoValueControlStatesEnum.LAST_SYNC_INFO_VALUE_STATE, 
439                                        UniversalTag.BOOLEAN_TAG, 
440                    new GrammarAction( "RefreshPresent refreshDone flag" )
441                {
442                    public void action( IAsn1Container container ) throws DecoderException
443                    {
444                        SyncInfoValueControlContainer syncInfoValueContainer = 
445                            ( SyncInfoValueControlContainer ) container;
446                        SyncInfoValueControl control = syncInfoValueContainer.getSyncInfoValueControl();
447                        
448                        Value value = syncInfoValueContainer.getCurrentTLV().getValue();
449    
450                        try
451                        {
452                            boolean refreshDone = BooleanDecoder.parse( value );
453    
454                            if ( IS_DEBUG )
455                            {
456                                LOG.debug( "refreshDone = {}", refreshDone );
457                            }
458    
459                            control.setRefreshDone( refreshDone );
460    
461                            syncInfoValueContainer.setSyncInfoValueControl( control );
462    
463                            // the END transition for grammar
464                            syncInfoValueContainer.grammarEndAllowed( true );
465                        }
466                        catch ( BooleanDecoderException be )
467                        {
468                            String msg = I18n.err( I18n.ERR_04025 );
469                            LOG.error( msg, be );
470                            throw new DecoderException( msg );
471                        }
472    
473                        // We can have an END transition
474                        syncInfoValueContainer.grammarEndAllowed( true );
475                    }
476                } );
477            
478            
479            /** 
480             * Transition from initial state to SyncInfoValue syncIdSet choice
481             * SyncInfoValue ::= CHOICE {
482             *     ...
483             *     syncIdSet [3] SEQUENCE {
484             *     ...
485             *     
486             * Initialize the syncInfoValue object
487             */
488            super.transitions[IStates.INIT_GRAMMAR_STATE][SyncInfoValueTags.SYNC_ID_SET_TAG.getValue()] = 
489                new GrammarTransition( IStates.INIT_GRAMMAR_STATE, 
490                                        SyncInfoValueControlStatesEnum.SYNC_ID_SET_STATE, 
491                                        SyncInfoValueTags.SYNC_ID_SET_TAG.getValue(), 
492                    new GrammarAction( "SyncIdSet choice for SyncInfoValueControl" )
493                {
494                    public void action( IAsn1Container container )
495                    {
496                        SyncInfoValueControlContainer syncInfoValueContainer = 
497                            ( SyncInfoValueControlContainer ) container;
498                        SyncInfoValueControl control = 
499                            new SyncInfoValueControl( SynchronizationInfoEnum.SYNC_ID_SET);
500                        
501                        syncInfoValueContainer.setSyncInfoValueControl( control );
502                    }
503                } );
504            
505            
506            /** 
507             * Transition from syncIdSet state to cookie
508             *     syncIdSet [3] SEQUENCE {
509             *         cookie syncCookie OPTIONAL,
510             *     ...
511             *     
512             * Load the cookie object
513             */
514            super.transitions[SyncInfoValueControlStatesEnum.SYNC_ID_SET_STATE][UniversalTag.OCTET_STRING_TAG] = 
515                new GrammarTransition( SyncInfoValueControlStatesEnum.SYNC_ID_SET_STATE, 
516                                        SyncInfoValueControlStatesEnum.SYNC_ID_SET_COOKIE_STATE, 
517                                        UniversalTag.OCTET_STRING_TAG, 
518                    new GrammarAction( "SyncIdSet cookie" )
519                {
520                    public void action( IAsn1Container container )
521                    {
522                        SyncInfoValueControlContainer syncInfoValueContainer = 
523                            ( SyncInfoValueControlContainer ) container;
524                        SyncInfoValueControl control = syncInfoValueContainer.getSyncInfoValueControl();
525                        
526                        Value value = syncInfoValueContainer.getCurrentTLV().getValue();
527    
528                        byte[] cookie = value.getData();
529    
530                        if ( IS_DEBUG )
531                        {
532                            LOG.debug( "cookie = " + StringTools.dumpBytes( cookie ) );
533                        }
534    
535                        syncInfoValueContainer.getSyncInfoValueControl().setCookie( cookie );
536                        syncInfoValueContainer.setSyncInfoValueControl( control );
537                    }
538                } );
539            
540            
541            /** 
542             * Transition from syncIdSet state to refreshDeletes
543             *     syncIdSet [3] SEQUENCE {
544             *         ...
545             *         refreshDeletes BOOLEAN DEFAULT FALSE,
546             *     ...
547             *     
548             * Load the refreshDeletes flag
549             */
550            super.transitions[SyncInfoValueControlStatesEnum.SYNC_ID_SET_STATE][UniversalTag.BOOLEAN_TAG] = 
551                new GrammarTransition( SyncInfoValueControlStatesEnum.SYNC_ID_SET_STATE, 
552                                        SyncInfoValueControlStatesEnum.SYNC_ID_SET_REFRESH_DELETES_STATE, 
553                                        UniversalTag.BOOLEAN_TAG, 
554                    new GrammarAction( "SyncIdSet refreshDeletes" )
555                {
556                    public void action( IAsn1Container container ) throws DecoderException
557                    {
558                        SyncInfoValueControlContainer syncInfoValueContainer = 
559                            ( SyncInfoValueControlContainer ) container;
560                        SyncInfoValueControl control = syncInfoValueContainer.getSyncInfoValueControl();
561                        
562                        Value value = syncInfoValueContainer.getCurrentTLV().getValue();
563    
564                        try
565                        {
566                            boolean refreshDeletes = BooleanDecoder.parse( value );
567    
568                            if ( IS_DEBUG )
569                            {
570                                LOG.debug( "refreshDeletes = {}", refreshDeletes );
571                            }
572    
573                            control.setRefreshDeletes( refreshDeletes );
574    
575                            syncInfoValueContainer.setSyncInfoValueControl( control );
576                        }
577                        catch ( BooleanDecoderException be )
578                        {
579                            String msg = I18n.err( I18n.ERR_04026 );
580                            LOG.error( msg, be );
581                            throw new DecoderException( msg );
582                        }
583                    }
584                } );
585            
586            
587            /** 
588             * Transition from syncIdSet cookie state to refreshDeletes
589             *     syncIdSet [3] SEQUENCE {
590             *         ...
591             *         refreshDeletes BOOLEAN DEFAULT FALSE,
592             *     ...
593             *     
594             * Load the refreshDeletes flag
595             */
596            super.transitions[SyncInfoValueControlStatesEnum.SYNC_ID_SET_COOKIE_STATE][UniversalTag.BOOLEAN_TAG] = 
597                new GrammarTransition( SyncInfoValueControlStatesEnum.SYNC_ID_SET_COOKIE_STATE, 
598                                        SyncInfoValueControlStatesEnum.SYNC_ID_SET_REFRESH_DELETES_STATE, 
599                                        UniversalTag.BOOLEAN_TAG, 
600                    new GrammarAction( "SyncIdSet refreshDeletes" )
601                {
602                    public void action( IAsn1Container container ) throws DecoderException
603                    {
604                        SyncInfoValueControlContainer syncInfoValueContainer = 
605                            ( SyncInfoValueControlContainer ) container;
606                        SyncInfoValueControl control = syncInfoValueContainer.getSyncInfoValueControl();
607                        
608                        Value value = syncInfoValueContainer.getCurrentTLV().getValue();
609    
610                        try
611                        {
612                            boolean refreshDeletes = BooleanDecoder.parse( value );
613    
614                            if ( IS_DEBUG )
615                            {
616                                LOG.debug( "refreshDeletes = {}", refreshDeletes );
617                            }
618    
619                            control.setRefreshDeletes( refreshDeletes );
620    
621                            syncInfoValueContainer.setSyncInfoValueControl( control );
622                        }
623                        catch ( BooleanDecoderException be )
624                        {
625                            String msg = I18n.err( I18n.ERR_04024 );
626                            LOG.error( msg, be );
627                            throw new DecoderException( msg );
628                        }
629                    }
630                } );
631            
632            
633            /** 
634             * Transition from syncIdSet state to syncUUIDs
635             *     syncIdSet [3] SEQUENCE {
636             *         ...
637             *         syncUUIDs      *SET OF* syncUUID
638             *     }
639             *     
640             * Initialize the UUID set : no action associated, except allowing a grammar end
641             */
642            super.transitions[SyncInfoValueControlStatesEnum.SYNC_ID_SET_STATE][UniversalTag.SET_TAG] = 
643                new GrammarTransition( SyncInfoValueControlStatesEnum.SYNC_ID_SET_STATE, 
644                                        SyncInfoValueControlStatesEnum.SYNC_ID_SET_SET_OF_UUIDS_STATE, 
645                                        UniversalTag.SET_TAG, 
646                    new GrammarAction( "SyncIdSet syncUUIDs" )
647                {
648                    public void action( IAsn1Container container ) throws DecoderException
649                    {
650                        SyncInfoValueControlContainer syncInfoValueContainer = 
651                            ( SyncInfoValueControlContainer ) container;
652    
653                        // We can have an END transition
654                        syncInfoValueContainer.grammarEndAllowed( true );
655                    }
656                } );
657            
658            
659            /** 
660             * Transition from syncIdSet cookie state to syncUUIDs
661             *     syncIdSet [3] SEQUENCE {
662             *         ...
663             *         syncUUIDs      *SET OF* syncUUID
664             *     }
665             *     
666             * Initialize the UUID set : no action associated
667             */
668            super.transitions[SyncInfoValueControlStatesEnum.SYNC_ID_SET_COOKIE_STATE][UniversalTag.SET_TAG] = 
669                new GrammarTransition( SyncInfoValueControlStatesEnum.SYNC_ID_SET_COOKIE_STATE, 
670                                        SyncInfoValueControlStatesEnum.SYNC_ID_SET_SET_OF_UUIDS_STATE, 
671                                        UniversalTag.SET_TAG,
672                    new GrammarAction( "SyncIdSet syncUUIDs" )
673                {
674                    public void action( IAsn1Container container ) throws DecoderException
675                    {
676                        SyncInfoValueControlContainer syncInfoValueContainer = 
677                            ( SyncInfoValueControlContainer ) container;
678    
679                        // We can have an END transition
680                        syncInfoValueContainer.grammarEndAllowed( true );
681                    }
682                } );
683              
684            
685            /** 
686             * Transition from syncIdSet refreshDeletes state to syncUUIDs
687             *     syncIdSet [3] SEQUENCE {
688             *         ...
689             *         syncUUIDs      *SET OF* syncUUID
690             *     }
691             *     
692             * Initialize the UUID set : no action associated
693             */
694            super.transitions[SyncInfoValueControlStatesEnum.SYNC_ID_SET_REFRESH_DELETES_STATE][UniversalTag.SET_TAG] = 
695                new GrammarTransition( SyncInfoValueControlStatesEnum.SYNC_ID_SET_REFRESH_DELETES_STATE, 
696                                        SyncInfoValueControlStatesEnum.SYNC_ID_SET_SET_OF_UUIDS_STATE, 
697                                        UniversalTag.SET_TAG, 
698                    new GrammarAction( "SyncIdSet syncUUIDs" )
699                {
700                    public void action( IAsn1Container container ) throws DecoderException
701                    {
702                        SyncInfoValueControlContainer syncInfoValueContainer = 
703                            ( SyncInfoValueControlContainer ) container;
704    
705                        // We can have an END transition
706                        syncInfoValueContainer.grammarEndAllowed( true );
707                    }
708                } );
709            
710            
711            /** 
712             * Transition from syncIdSet syncUUIDs to syncUUID
713             *     syncIdSet [3] SEQUENCE {
714             *         ...
715             *         syncUUIDs      SET OF *syncUUID*
716             *     }
717             *     
718             * Add the first UUID in the UUIDs list
719             */
720            super.transitions[SyncInfoValueControlStatesEnum.SYNC_ID_SET_SET_OF_UUIDS_STATE][UniversalTag.OCTET_STRING] = 
721                new GrammarTransition( SyncInfoValueControlStatesEnum.SYNC_ID_SET_SET_OF_UUIDS_STATE, 
722                                        SyncInfoValueControlStatesEnum.SYNC_ID_SET_UUID_STATE, 
723                                        UniversalTag.OCTET_STRING, 
724                    new GrammarAction( "SyncIdSet first UUID" )
725                {
726                    public void action( IAsn1Container container ) throws DecoderException
727                    {
728                        SyncInfoValueControlContainer syncInfoValueContainer = 
729                            ( SyncInfoValueControlContainer ) container;
730                        SyncInfoValueControl control = syncInfoValueContainer.getSyncInfoValueControl();
731                        
732                        Value value = syncInfoValueContainer.getCurrentTLV().getValue();
733    
734                        byte[] uuid = value.getData();
735                        
736                        // UUID must be exactly 16 bytes long
737                        if ( ( uuid == null ) || ( uuid.length != 16 ) )
738                        {
739                            String msg = I18n.err( I18n.ERR_04027 );
740                            LOG.error( msg );
741                            throw new DecoderException( msg );
742                        }
743    
744                        if ( IS_DEBUG )
745                        {
746                            LOG.debug( "UUID = " + StringTools.dumpBytes( uuid ) );
747                        }
748    
749                        // Store the UUID in the UUIDs list
750                        control.getSyncUUIDs().add( uuid );
751                        
752                        // We can have an END transition
753                        syncInfoValueContainer.grammarEndAllowed( true );
754                    }
755                } );
756            
757            
758            /** 
759             * Transition from syncIdSet syncUUID to syncUUID
760             *     syncIdSet [3] SEQUENCE {
761             *         ...
762             *         syncUUIDs      SET OF *syncUUID*
763             *     }
764             *     
765             * Add a new UUID in the UUIDs list
766             */
767            super.transitions[SyncInfoValueControlStatesEnum.SYNC_ID_SET_UUID_STATE][UniversalTag.OCTET_STRING] = 
768                new GrammarTransition( SyncInfoValueControlStatesEnum.SYNC_ID_SET_UUID_STATE, 
769                                        SyncInfoValueControlStatesEnum.SYNC_ID_SET_UUID_STATE, 
770                                        UniversalTag.OCTET_STRING, 
771                    new GrammarAction( "SyncIdSet UUID" )
772                {
773                    public void action( IAsn1Container container ) throws DecoderException
774                    {
775                        SyncInfoValueControlContainer syncInfoValueContainer = 
776                            ( SyncInfoValueControlContainer ) container;
777                        SyncInfoValueControl control = syncInfoValueContainer.getSyncInfoValueControl();
778                        
779                        Value value = syncInfoValueContainer.getCurrentTLV().getValue();
780    
781                        byte[] uuid = value.getData();
782                        
783                        // UUID must be exactly 16 bytes long
784                        if ( ( uuid == null ) || ( uuid.length != 16 ) )
785                        {
786                            String msg = I18n.err( I18n.ERR_04027 );
787                            LOG.error( msg );
788                            throw new DecoderException( msg );
789                        }
790    
791                        if ( IS_DEBUG )
792                        {
793                            LOG.debug( "UUID = " + StringTools.dumpBytes( uuid ) );
794                        }
795    
796                        // Store the UUID in the UUIDs list
797                        control.getSyncUUIDs().add( uuid );
798                        
799                        // We can have an END transition
800                        syncInfoValueContainer.grammarEndAllowed( true );
801                    }
802                } );
803        }
804    
805    
806        /**
807         * This class is a singleton.
808         * 
809         * @return An instance on this grammar
810         */
811        public static IGrammar getInstance()
812        {
813            return instance;
814        }
815    }