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