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.transfer.AbstractTransferListener; 028import org.eclipse.aether.transfer.TransferCancelledException; 029import org.eclipse.aether.transfer.TransferEvent; 030import org.eclipse.aether.transfer.TransferListener; 031 032import static java.util.Objects.requireNonNull; 033 034/** 035 * A transfer listener that delegates to zero or more other listeners (multicast). The list of target listeners is 036 * thread-safe, i.e. target listeners can be added or removed by any thread at any time. 037 */ 038public final class ChainedTransferListener 039 extends AbstractTransferListener 040{ 041 042 private final List<TransferListener> listeners = new CopyOnWriteArrayList<>(); 043 044 /** 045 * Creates a new multicast listener that delegates to the specified listeners. In contrast to the constructor, this 046 * factory method will avoid creating an actual chained listener if one of the specified readers is actually 047 * {@code null}. 048 * 049 * @param listener1 The first listener, may be {@code null}. 050 * @param listener2 The second listener, may be {@code null}. 051 * @return The chained listener or {@code null} if no listener was supplied. 052 */ 053 public static TransferListener newInstance( TransferListener listener1, TransferListener listener2 ) 054 { 055 if ( listener1 == null ) 056 { 057 return listener2; 058 } 059 else if ( listener2 == null ) 060 { 061 return listener1; 062 } 063 return new ChainedTransferListener( listener1, listener2 ); 064 } 065 066 /** 067 * Creates a new multicast listener that delegates to the specified listeners. 068 * 069 * @param listeners The listeners to delegate to, may be {@code null} or empty. 070 */ 071 public ChainedTransferListener( TransferListener... listeners ) 072 { 073 if ( listeners != null ) 074 { 075 add( Arrays.asList( listeners ) ); 076 } 077 } 078 079 /** 080 * Creates a new multicast listener that delegates to the specified listeners. 081 * 082 * @param listeners The listeners to delegate to, may be {@code null} or empty. 083 */ 084 public ChainedTransferListener( Collection<? extends TransferListener> listeners ) 085 { 086 add( listeners ); 087 } 088 089 /** 090 * Adds the specified listeners to the end of the multicast chain. 091 * 092 * @param listeners The listeners to add, may be {@code null} or empty. 093 */ 094 public void add( Collection<? extends TransferListener> listeners ) 095 { 096 if ( listeners != null ) 097 { 098 for ( TransferListener listener : listeners ) 099 { 100 add( listener ); 101 } 102 } 103 } 104 105 /** 106 * Adds the specified listener to the end of the multicast chain. 107 * 108 * @param listener The listener to add, may be {@code null}. 109 */ 110 public void add( TransferListener listener ) 111 { 112 if ( listener != null ) 113 { 114 listeners.add( listener ); 115 } 116 } 117 118 /** 119 * Removes the specified listener from the multicast chain. Trying to remove a non-existing listener has no effect. 120 * 121 * @param listener The listener to remove, may be {@code null}. 122 */ 123 public void remove( TransferListener listener ) 124 { 125 if ( listener != null ) 126 { 127 listeners.remove( listener ); 128 } 129 } 130 131 @SuppressWarnings( "EmptyMethod" ) 132 protected void handleError( TransferEvent event, TransferListener listener, RuntimeException error ) 133 { 134 // default just swallows errors 135 } 136 137 @Override 138 public void transferInitiated( TransferEvent event ) 139 throws TransferCancelledException 140 { 141 requireNonNull( event, "event cannot be null" ); 142 for ( TransferListener listener : listeners ) 143 { 144 try 145 { 146 listener.transferInitiated( event ); 147 } 148 catch ( RuntimeException e ) 149 { 150 handleError( event, listener, e ); 151 } 152 } 153 } 154 155 @Override 156 public void transferStarted( TransferEvent event ) 157 throws TransferCancelledException 158 { 159 requireNonNull( event, "event cannot be null" ); 160 for ( TransferListener listener : listeners ) 161 { 162 try 163 { 164 listener.transferStarted( event ); 165 } 166 catch ( RuntimeException e ) 167 { 168 handleError( event, listener, e ); 169 } 170 } 171 } 172 173 @Override 174 public void transferProgressed( TransferEvent event ) 175 throws TransferCancelledException 176 { 177 requireNonNull( event, "event cannot be null" ); 178 for ( TransferListener listener : listeners ) 179 { 180 try 181 { 182 listener.transferProgressed( event ); 183 } 184 catch ( RuntimeException e ) 185 { 186 handleError( event, listener, e ); 187 } 188 } 189 } 190 191 @Override 192 public void transferCorrupted( TransferEvent event ) 193 throws TransferCancelledException 194 { 195 requireNonNull( event, "event cannot be null" ); 196 for ( TransferListener listener : listeners ) 197 { 198 try 199 { 200 listener.transferCorrupted( event ); 201 } 202 catch ( RuntimeException e ) 203 { 204 handleError( event, listener, e ); 205 } 206 } 207 } 208 209 @Override 210 public void transferSucceeded( TransferEvent event ) 211 { 212 requireNonNull( event, "event cannot be null" ); 213 for ( TransferListener listener : listeners ) 214 { 215 try 216 { 217 listener.transferSucceeded( event ); 218 } 219 catch ( RuntimeException e ) 220 { 221 handleError( event, listener, e ); 222 } 223 } 224 } 225 226 @Override 227 public void transferFailed( TransferEvent event ) 228 { 229 requireNonNull( event, "event cannot be null" ); 230 for ( TransferListener listener : listeners ) 231 { 232 try 233 { 234 listener.transferFailed( event ); 235 } 236 catch ( RuntimeException e ) 237 { 238 handleError( event, listener, e ); 239 } 240 } 241 } 242 243}