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