001package org.eclipse.aether.util.listener;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 * 
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 * 
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.Arrays;
023import java.util.Collection;
024import java.util.List;
025import java.util.concurrent.CopyOnWriteArrayList;
026
027import org.eclipse.aether.AbstractRepositoryListener;
028import org.eclipse.aether.RepositoryEvent;
029import org.eclipse.aether.RepositoryListener;
030
031/**
032 * A repository listener that delegates to zero or more other listeners (multicast). The list of target listeners is
033 * thread-safe, i.e. target listeners can be added or removed by any thread at any time.
034 */
035public final class ChainedRepositoryListener
036    extends AbstractRepositoryListener
037{
038
039    private final List<RepositoryListener> listeners = new CopyOnWriteArrayList<>();
040
041    /**
042     * Creates a new multicast listener that delegates to the specified listeners. In contrast to the constructor, this
043     * factory method will avoid creating an actual chained listener if one of the specified readers is actually
044     * {@code null}.
045     * 
046     * @param listener1 The first listener, may be {@code null}.
047     * @param listener2 The second listener, may be {@code null}.
048     * @return The chained listener or {@code null} if no listener was supplied.
049     */
050    public static RepositoryListener newInstance( RepositoryListener listener1, RepositoryListener listener2 )
051    {
052        if ( listener1 == null )
053        {
054            return listener2;
055        }
056        else if ( listener2 == null )
057        {
058            return listener1;
059        }
060        return new ChainedRepositoryListener( listener1, listener2 );
061    }
062
063    /**
064     * Creates a new multicast listener that delegates to the specified listeners.
065     * 
066     * @param listeners The listeners to delegate to, may be {@code null} or empty.
067     */
068    public ChainedRepositoryListener( RepositoryListener... listeners )
069    {
070        if ( listeners != null )
071        {
072            add( Arrays.asList( listeners ) );
073        }
074    }
075
076    /**
077     * Creates a new multicast listener that delegates to the specified listeners.
078     * 
079     * @param listeners The listeners to delegate to, may be {@code null} or empty.
080     */
081    public ChainedRepositoryListener( Collection<? extends RepositoryListener> listeners )
082    {
083        add( listeners );
084    }
085
086    /**
087     * Adds the specified listeners to the end of the multicast chain.
088     * 
089     * @param listeners The listeners to add, may be {@code null} or empty.
090     */
091    public void add( Collection<? extends RepositoryListener> listeners )
092    {
093        if ( listeners != null )
094        {
095            for ( RepositoryListener listener : listeners )
096            {
097                add( listener );
098            }
099        }
100    }
101
102    /**
103     * Adds the specified listener to the end of the multicast chain.
104     * 
105     * @param listener The listener to add, may be {@code null}.
106     */
107    public void add( RepositoryListener listener )
108    {
109        if ( listener != null )
110        {
111            listeners.add( listener );
112        }
113    }
114
115    /**
116     * Removes the specified listener from the multicast chain. Trying to remove a non-existing listener has no effect.
117     * 
118     * @param listener The listener to remove, may be {@code null}.
119     */
120    public void remove( RepositoryListener listener )
121    {
122        if ( listener != null )
123        {
124            listeners.remove( listener );
125        }
126    }
127
128    @SuppressWarnings( "EmptyMethod" )
129    protected void handleError( RepositoryEvent event, RepositoryListener listener, RuntimeException error )
130    {
131        // default just swallows errors
132    }
133
134    @Override
135    public void artifactDeployed( RepositoryEvent event )
136    {
137        for ( RepositoryListener listener : listeners )
138        {
139            try
140            {
141                listener.artifactDeployed( event );
142            }
143            catch ( RuntimeException e )
144            {
145                handleError( event, listener, e );
146            }
147        }
148    }
149
150    @Override
151    public void artifactDeploying( RepositoryEvent event )
152    {
153        for ( RepositoryListener listener : listeners )
154        {
155            try
156            {
157                listener.artifactDeploying( event );
158            }
159            catch ( RuntimeException e )
160            {
161                handleError( event, listener, e );
162            }
163        }
164    }
165
166    @Override
167    public void artifactDescriptorInvalid( RepositoryEvent event )
168    {
169        for ( RepositoryListener listener : listeners )
170        {
171            try
172            {
173                listener.artifactDescriptorInvalid( event );
174            }
175            catch ( RuntimeException e )
176            {
177                handleError( event, listener, e );
178            }
179        }
180    }
181
182    @Override
183    public void artifactDescriptorMissing( RepositoryEvent event )
184    {
185        for ( RepositoryListener listener : listeners )
186        {
187            try
188            {
189                listener.artifactDescriptorMissing( event );
190            }
191            catch ( RuntimeException e )
192            {
193                handleError( event, listener, e );
194            }
195        }
196    }
197
198    @Override
199    public void artifactDownloaded( RepositoryEvent event )
200    {
201        for ( RepositoryListener listener : listeners )
202        {
203            try
204            {
205                listener.artifactDownloaded( event );
206            }
207            catch ( RuntimeException e )
208            {
209                handleError( event, listener, e );
210            }
211        }
212    }
213
214    @Override
215    public void artifactDownloading( RepositoryEvent event )
216    {
217        for ( RepositoryListener listener : listeners )
218        {
219            try
220            {
221                listener.artifactDownloading( event );
222            }
223            catch ( RuntimeException e )
224            {
225                handleError( event, listener, e );
226            }
227        }
228    }
229
230    @Override
231    public void artifactInstalled( RepositoryEvent event )
232    {
233        for ( RepositoryListener listener : listeners )
234        {
235            try
236            {
237                listener.artifactInstalled( event );
238            }
239            catch ( RuntimeException e )
240            {
241                handleError( event, listener, e );
242            }
243        }
244    }
245
246    @Override
247    public void artifactInstalling( RepositoryEvent event )
248    {
249        for ( RepositoryListener listener : listeners )
250        {
251            try
252            {
253                listener.artifactInstalling( event );
254            }
255            catch ( RuntimeException e )
256            {
257                handleError( event, listener, e );
258            }
259        }
260    }
261
262    @Override
263    public void artifactResolved( RepositoryEvent event )
264    {
265        for ( RepositoryListener listener : listeners )
266        {
267            try
268            {
269                listener.artifactResolved( event );
270            }
271            catch ( RuntimeException e )
272            {
273                handleError( event, listener, e );
274            }
275        }
276    }
277
278    @Override
279    public void artifactResolving( RepositoryEvent event )
280    {
281        for ( RepositoryListener listener : listeners )
282        {
283            try
284            {
285                listener.artifactResolving( event );
286            }
287            catch ( RuntimeException e )
288            {
289                handleError( event, listener, e );
290            }
291        }
292    }
293
294    @Override
295    public void metadataDeployed( RepositoryEvent event )
296    {
297        for ( RepositoryListener listener : listeners )
298        {
299            try
300            {
301                listener.metadataDeployed( event );
302            }
303            catch ( RuntimeException e )
304            {
305                handleError( event, listener, e );
306            }
307        }
308    }
309
310    @Override
311    public void metadataDeploying( RepositoryEvent event )
312    {
313        for ( RepositoryListener listener : listeners )
314        {
315            try
316            {
317                listener.metadataDeploying( event );
318            }
319            catch ( RuntimeException e )
320            {
321                handleError( event, listener, e );
322            }
323        }
324    }
325
326    @Override
327    public void metadataDownloaded( RepositoryEvent event )
328    {
329        for ( RepositoryListener listener : listeners )
330        {
331            try
332            {
333                listener.metadataDownloaded( event );
334            }
335            catch ( RuntimeException e )
336            {
337                handleError( event, listener, e );
338            }
339        }
340    }
341
342    @Override
343    public void metadataDownloading( RepositoryEvent event )
344    {
345        for ( RepositoryListener listener : listeners )
346        {
347            try
348            {
349                listener.metadataDownloading( event );
350            }
351            catch ( RuntimeException e )
352            {
353                handleError( event, listener, e );
354            }
355        }
356    }
357
358    @Override
359    public void metadataInstalled( RepositoryEvent event )
360    {
361        for ( RepositoryListener listener : listeners )
362        {
363            try
364            {
365                listener.metadataInstalled( event );
366            }
367            catch ( RuntimeException e )
368            {
369                handleError( event, listener, e );
370            }
371        }
372    }
373
374    @Override
375    public void metadataInstalling( RepositoryEvent event )
376    {
377        for ( RepositoryListener listener : listeners )
378        {
379            try
380            {
381                listener.metadataInstalling( event );
382            }
383            catch ( RuntimeException e )
384            {
385                handleError( event, listener, e );
386            }
387        }
388    }
389
390    @Override
391    public void metadataInvalid( RepositoryEvent event )
392    {
393        for ( RepositoryListener listener : listeners )
394        {
395            try
396            {
397                listener.metadataInvalid( event );
398            }
399            catch ( RuntimeException e )
400            {
401                handleError( event, listener, e );
402            }
403        }
404    }
405
406    @Override
407    public void metadataResolved( RepositoryEvent event )
408    {
409        for ( RepositoryListener listener : listeners )
410        {
411            try
412            {
413                listener.metadataResolved( event );
414            }
415            catch ( RuntimeException e )
416            {
417                handleError( event, listener, e );
418            }
419        }
420    }
421
422    @Override
423    public void metadataResolving( RepositoryEvent event )
424    {
425        for ( RepositoryListener listener : listeners )
426        {
427            try
428            {
429                listener.metadataResolving( event );
430            }
431            catch ( RuntimeException e )
432            {
433                handleError( event, listener, e );
434            }
435        }
436    }
437
438}