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<RepositoryListener>();
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    protected void handleError( RepositoryEvent event, RepositoryListener listener, RuntimeException error )
129    {
130        // default just swallows errors
131    }
132
133    @Override
134    public void artifactDeployed( RepositoryEvent event )
135    {
136        for ( RepositoryListener listener : listeners )
137        {
138            try
139            {
140                listener.artifactDeployed( event );
141            }
142            catch ( RuntimeException e )
143            {
144                handleError( event, listener, e );
145            }
146        }
147    }
148
149    @Override
150    public void artifactDeploying( RepositoryEvent event )
151    {
152        for ( RepositoryListener listener : listeners )
153        {
154            try
155            {
156                listener.artifactDeploying( event );
157            }
158            catch ( RuntimeException e )
159            {
160                handleError( event, listener, e );
161            }
162        }
163    }
164
165    @Override
166    public void artifactDescriptorInvalid( RepositoryEvent event )
167    {
168        for ( RepositoryListener listener : listeners )
169        {
170            try
171            {
172                listener.artifactDescriptorInvalid( event );
173            }
174            catch ( RuntimeException e )
175            {
176                handleError( event, listener, e );
177            }
178        }
179    }
180
181    @Override
182    public void artifactDescriptorMissing( RepositoryEvent event )
183    {
184        for ( RepositoryListener listener : listeners )
185        {
186            try
187            {
188                listener.artifactDescriptorMissing( event );
189            }
190            catch ( RuntimeException e )
191            {
192                handleError( event, listener, e );
193            }
194        }
195    }
196
197    @Override
198    public void artifactDownloaded( RepositoryEvent event )
199    {
200        for ( RepositoryListener listener : listeners )
201        {
202            try
203            {
204                listener.artifactDownloaded( event );
205            }
206            catch ( RuntimeException e )
207            {
208                handleError( event, listener, e );
209            }
210        }
211    }
212
213    @Override
214    public void artifactDownloading( RepositoryEvent event )
215    {
216        for ( RepositoryListener listener : listeners )
217        {
218            try
219            {
220                listener.artifactDownloading( event );
221            }
222            catch ( RuntimeException e )
223            {
224                handleError( event, listener, e );
225            }
226        }
227    }
228
229    @Override
230    public void artifactInstalled( RepositoryEvent event )
231    {
232        for ( RepositoryListener listener : listeners )
233        {
234            try
235            {
236                listener.artifactInstalled( event );
237            }
238            catch ( RuntimeException e )
239            {
240                handleError( event, listener, e );
241            }
242        }
243    }
244
245    @Override
246    public void artifactInstalling( RepositoryEvent event )
247    {
248        for ( RepositoryListener listener : listeners )
249        {
250            try
251            {
252                listener.artifactInstalling( event );
253            }
254            catch ( RuntimeException e )
255            {
256                handleError( event, listener, e );
257            }
258        }
259    }
260
261    @Override
262    public void artifactResolved( RepositoryEvent event )
263    {
264        for ( RepositoryListener listener : listeners )
265        {
266            try
267            {
268                listener.artifactResolved( event );
269            }
270            catch ( RuntimeException e )
271            {
272                handleError( event, listener, e );
273            }
274        }
275    }
276
277    @Override
278    public void artifactResolving( RepositoryEvent event )
279    {
280        for ( RepositoryListener listener : listeners )
281        {
282            try
283            {
284                listener.artifactResolving( event );
285            }
286            catch ( RuntimeException e )
287            {
288                handleError( event, listener, e );
289            }
290        }
291    }
292
293    @Override
294    public void metadataDeployed( RepositoryEvent event )
295    {
296        for ( RepositoryListener listener : listeners )
297        {
298            try
299            {
300                listener.metadataDeployed( event );
301            }
302            catch ( RuntimeException e )
303            {
304                handleError( event, listener, e );
305            }
306        }
307    }
308
309    @Override
310    public void metadataDeploying( RepositoryEvent event )
311    {
312        for ( RepositoryListener listener : listeners )
313        {
314            try
315            {
316                listener.metadataDeploying( event );
317            }
318            catch ( RuntimeException e )
319            {
320                handleError( event, listener, e );
321            }
322        }
323    }
324
325    @Override
326    public void metadataDownloaded( RepositoryEvent event )
327    {
328        for ( RepositoryListener listener : listeners )
329        {
330            try
331            {
332                listener.metadataDownloaded( event );
333            }
334            catch ( RuntimeException e )
335            {
336                handleError( event, listener, e );
337            }
338        }
339    }
340
341    @Override
342    public void metadataDownloading( RepositoryEvent event )
343    {
344        for ( RepositoryListener listener : listeners )
345        {
346            try
347            {
348                listener.metadataDownloading( event );
349            }
350            catch ( RuntimeException e )
351            {
352                handleError( event, listener, e );
353            }
354        }
355    }
356
357    @Override
358    public void metadataInstalled( RepositoryEvent event )
359    {
360        for ( RepositoryListener listener : listeners )
361        {
362            try
363            {
364                listener.metadataInstalled( event );
365            }
366            catch ( RuntimeException e )
367            {
368                handleError( event, listener, e );
369            }
370        }
371    }
372
373    @Override
374    public void metadataInstalling( RepositoryEvent event )
375    {
376        for ( RepositoryListener listener : listeners )
377        {
378            try
379            {
380                listener.metadataInstalling( event );
381            }
382            catch ( RuntimeException e )
383            {
384                handleError( event, listener, e );
385            }
386        }
387    }
388
389    @Override
390    public void metadataInvalid( RepositoryEvent event )
391    {
392        for ( RepositoryListener listener : listeners )
393        {
394            try
395            {
396                listener.metadataInvalid( event );
397            }
398            catch ( RuntimeException e )
399            {
400                handleError( event, listener, e );
401            }
402        }
403    }
404
405    @Override
406    public void metadataResolved( RepositoryEvent event )
407    {
408        for ( RepositoryListener listener : listeners )
409        {
410            try
411            {
412                listener.metadataResolved( event );
413            }
414            catch ( RuntimeException e )
415            {
416                handleError( event, listener, e );
417            }
418        }
419    }
420
421    @Override
422    public void metadataResolving( RepositoryEvent event )
423    {
424        for ( RepositoryListener listener : listeners )
425        {
426            try
427            {
428                listener.metadataResolving( event );
429            }
430            catch ( RuntimeException e )
431            {
432                handleError( event, listener, e );
433            }
434        }
435    }
436
437}