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