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.syncInfoValue;
021
022
023import java.util.ArrayList;
024import java.util.Arrays;
025import java.util.List;
026
027import org.apache.directory.api.ldap.model.message.controls.AbstractControl;
028import org.apache.directory.api.util.Strings;
029
030
031/**
032 * A simple {@link SyncInfoValue} implementation to store control properties.
033 *
034 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
035 * @version $Rev$, $Date$
036 */
037public class SyncInfoValueImpl extends AbstractControl implements SyncInfoValue
038{
039    /** The kind of syncInfoValue we are dealing with */
040    private SynchronizationInfoEnum type;
041
042    /** The cookie */
043    private byte[] cookie;
044
045    /** The refreshDone flag if we are dealing with refreshXXX syncInfo. Default to true */
046    private boolean refreshDone = true;
047
048    /** The refreshDeletes flag if we are dealing with syncIdSet syncInfo. Defaults to false */
049    private boolean refreshDeletes = false;
050
051    /** The list of UUIDs if we are dealing with syncIdSet syncInfo */
052    private List<byte[]> syncUUIDs;
053
054
055    /**
056     * Creates a new instance of SyncInfoValueImpl.
057     */
058    public SyncInfoValueImpl()
059    {
060        super( OID );
061    }
062
063
064    /**
065     *
066     * Creates a new instance of SyncInfoValueImpl.
067     *
068     * @param isCritical The critical flag
069     */
070    public SyncInfoValueImpl( boolean isCritical )
071    {
072        super( OID, isCritical );
073    }
074
075
076    /**
077     * {@inheritDoc}
078     */
079    @Override
080    public SynchronizationInfoEnum getType()
081    {
082        return type;
083    }
084
085
086    /**
087     * {@inheritDoc}
088     */
089    @Override
090    public void setType( SynchronizationInfoEnum type )
091    {
092        this.type = type;
093    }
094
095
096    /**
097     * {@inheritDoc}
098     */
099    @Override
100    public byte[] getCookie()
101    {
102        return cookie;
103    }
104
105
106    /**
107     * {@inheritDoc}
108     */
109    @Override
110    public void setCookie( byte[] cookie )
111    {
112        this.cookie = cookie;
113    }
114
115
116    /**
117     * {@inheritDoc}
118     */
119    @Override
120    public boolean isRefreshDone()
121    {
122        return refreshDone;
123    }
124
125
126    /**
127     * {@inheritDoc}
128     */
129    @Override
130    public void setRefreshDone( boolean refreshDone )
131    {
132        this.refreshDone = refreshDone;
133    }
134
135
136    /**
137     * {@inheritDoc}
138     */
139    @Override
140    public boolean isRefreshDeletes()
141    {
142        return refreshDeletes;
143    }
144
145
146    /**
147     * {@inheritDoc}
148     */
149    @Override
150    public void setRefreshDeletes( boolean refreshDeletes )
151    {
152        this.refreshDeletes = refreshDeletes;
153    }
154
155
156    /**
157     * {@inheritDoc}
158     */
159    @Override
160    public List<byte[]> getSyncUUIDs()
161    {
162        return syncUUIDs;
163    }
164
165
166    /**
167     * {@inheritDoc}
168     */
169    @Override
170    public void setSyncUUIDs( List<byte[]> syncUUIDs )
171    {
172        this.syncUUIDs = syncUUIDs;
173    }
174
175
176    /**
177     * {@inheritDoc}
178     */
179    @Override
180    public void addSyncUUID( byte[] syncUUID )
181    {
182        if ( syncUUIDs == null )
183        {
184            syncUUIDs = new ArrayList<>();
185        }
186
187        syncUUIDs.add( syncUUID );
188    }
189
190
191    /**
192     * @see Object#hashCode()
193     */
194    @Override
195    public int hashCode()
196    {
197        int h = 37;
198
199        h = h * 17 + super.hashCode();
200        h = h * 17 + type.getValue();
201        h = h * 17 + ( refreshDone ? 1 : 0 );
202        h = h * 17 + ( refreshDeletes ? 1 : 0 );
203
204        if ( cookie != null )
205        {
206            for ( byte b : cookie )
207            {
208                h = h * 17 + b;
209            }
210        }
211
212        if ( syncUUIDs != null )
213        {
214            for ( byte[] bytes : syncUUIDs )
215            {
216                if ( bytes != null )
217                {
218                    for ( byte b : bytes )
219                    {
220                        h = h * 17 + b;
221                    }
222                }
223            }
224        }
225
226        return h;
227    }
228
229
230    /**
231     * @see Object#equals(Object)
232     */
233    @Override
234    public boolean equals( Object o )
235    {
236        if ( this == o )
237        {
238            return true;
239        }
240
241        if ( !( o instanceof SyncInfoValue ) )
242        {
243            return false;
244        }
245
246        SyncInfoValue otherControl = ( SyncInfoValue ) o;
247
248        if ( syncUUIDs != null )
249        {
250            if ( otherControl.getSyncUUIDs() == null )
251            {
252                return false;
253            }
254
255            // @TODO : this is extremely heavy... We have to find a better way to
256            // compare the lists of suncUuids, but atm, it's enough.
257            for ( byte[] syncUuid : syncUUIDs )
258            {
259                boolean found = false;
260
261                for ( byte[] otherSyncUuid : otherControl.getSyncUUIDs() )
262                {
263                    if ( Arrays.equals( syncUuid, otherSyncUuid ) )
264                    {
265                        found = true;
266                        break;
267                    }
268                }
269
270                if ( !found )
271                {
272                    return false;
273                }
274            }
275        }
276        else
277        {
278            if ( otherControl.getSyncUUIDs() != null )
279            {
280                return false;
281            }
282        }
283
284        return ( refreshDeletes == otherControl.isRefreshDeletes() )
285            && ( refreshDone == otherControl.isRefreshDone() )
286            && ( type == otherControl.getType() )
287            && ( Arrays.equals( cookie, otherControl.getCookie() ) ) 
288            && ( isCritical() == otherControl.isCritical() );
289    }
290
291
292    /**
293     * @see Object#toString()
294     */
295    @Override
296    public String toString()
297    {
298        StringBuilder sb = new StringBuilder();
299
300        sb.append( "    SyncInfoValue control :\n" );
301        sb.append( "        oid : " ).append( getOid() ).append( '\n' );
302        sb.append( "        critical : " ).append( isCritical() ).append( '\n' );
303
304        switch ( getType() )
305        {
306            case NEW_COOKIE:
307                sb.append( "        newCookie : '" ).
308                    append( Strings.utf8ToString( getCookie() ) ).append( "'\n" );
309                break;
310
311            case REFRESH_DELETE:
312                sb.append( "        refreshDelete : \n" );
313
314                if ( getCookie() != null )
315                {
316                    sb.append( "            cookie : '" ).
317                        append( Strings.dumpBytes( getCookie() ) ).append( "'\n" );
318                }
319
320                sb.append( "            refreshDone : " ).append( isRefreshDone() ).append( '\n' );
321                break;
322
323            case REFRESH_PRESENT:
324                sb.append( "        refreshPresent : \n" );
325
326                if ( getCookie() != null )
327                {
328                    sb.append( "            cookie : '" ).
329                        append( Strings.dumpBytes( getCookie() ) ).append( "'\n" );
330                }
331
332                sb.append( "            refreshDone : " ).append( isRefreshDone() ).append( '\n' );
333                break;
334
335            case SYNC_ID_SET:
336                sb.append( "        syncIdSet : \n" );
337
338                if ( getCookie() != null )
339                {
340                    sb.append( "            cookie : '" ).
341                        append( Strings.dumpBytes( getCookie() ) ).append( "'\n" );
342                }
343
344                sb.append( "            refreshDeletes : " ).append( isRefreshDeletes() ).append( '\n' );
345                sb.append( "            syncUUIDS : " );
346
347                if ( !getSyncUUIDs().isEmpty() )
348                {
349                    boolean isFirst = true;
350
351                    for ( byte[] syncUUID : getSyncUUIDs() )
352                    {
353                        if ( isFirst )
354                        {
355                            isFirst = false;
356                        }
357                        else
358                        {
359                            sb.append( ", " );
360                        }
361
362                        sb.append( Arrays.toString( syncUUID ) );
363                    }
364
365                    sb.append( '\n' );
366                }
367                else
368                {
369                    sb.append( "empty\n" );
370                }
371
372                break;
373
374            default:
375                throw new IllegalArgumentException( "Unexpected SynchronizationInfo: " + getType() );
376        }
377
378        return sb.toString();
379    }
380}