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