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 */ 019package org.eclipse.aether.util.listener; 020 021import java.util.Arrays; 022import java.util.Collection; 023import java.util.List; 024import java.util.concurrent.CopyOnWriteArrayList; 025import java.util.logging.Level; 026import java.util.logging.Logger; 027 028import org.eclipse.aether.AbstractRepositoryListener; 029import org.eclipse.aether.RepositoryEvent; 030import org.eclipse.aether.RepositoryListener; 031 032import static java.util.Objects.requireNonNull; 033 034/** 035 * A repository 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 class ChainedRepositoryListener extends AbstractRepositoryListener { 039 040 private final List<RepositoryListener> listeners = new CopyOnWriteArrayList<>(); 041 042 /** 043 * Creates a new multicast listener that delegates to the specified listeners. In contrast to the constructor, this 044 * factory method will avoid creating an actual chained listener if one of the specified readers is actually 045 * {@code null}. 046 * 047 * @param listener1 the first listener, may be {@code null} 048 * @param listener2 the second listener, may be {@code null} 049 * @return the chained listener or {@code null} if no listener was supplied 050 */ 051 public static RepositoryListener newInstance(RepositoryListener listener1, RepositoryListener listener2) { 052 if (listener1 == null) { 053 return listener2; 054 } else if (listener2 == null) { 055 return listener1; 056 } 057 return new ChainedRepositoryListener(listener1, listener2); 058 } 059 060 /** 061 * Creates a new multicast listener that delegates to the specified listeners. 062 * 063 * @param listeners the listeners to delegate to, may be {@code null} or empty 064 */ 065 public ChainedRepositoryListener(RepositoryListener... listeners) { 066 if (listeners != null) { 067 add(Arrays.asList(listeners)); 068 } 069 } 070 071 /** 072 * Creates a new multicast listener that delegates to the specified listeners. 073 * 074 * @param listeners the listeners to delegate to, may be {@code null} or empty 075 */ 076 public ChainedRepositoryListener(Collection<? extends RepositoryListener> listeners) { 077 add(listeners); 078 } 079 080 /** 081 * Adds the specified listeners to the end of the multicast chain. 082 * 083 * @param listeners the listeners to add, may be {@code null} or empty 084 */ 085 public void add(Collection<? extends RepositoryListener> listeners) { 086 if (listeners != null) { 087 for (RepositoryListener listener : listeners) { 088 add(listener); 089 } 090 } 091 } 092 093 /** 094 * Adds the specified listener to the end of the multicast chain. 095 * 096 * @param listener the listener to add, may be {@code null} 097 */ 098 public void add(RepositoryListener listener) { 099 if (listener != null) { 100 listeners.add(listener); 101 } 102 } 103 104 /** 105 * Removes the specified listener from the multicast chain. Trying to remove a non-existing listener has no effect. 106 * 107 * @param listener the listener to remove, may be {@code null} 108 */ 109 public void remove(RepositoryListener listener) { 110 if (listener != null) { 111 listeners.remove(listener); 112 } 113 } 114 115 private static final Logger LOGGER = Logger.getLogger(ChainedRepositoryListener.class.getName()); 116 117 /** 118 * Invoked when any listener throws, by default logs a warning, extend if required. 119 */ 120 protected void handleError(RepositoryEvent event, RepositoryListener listener, RuntimeException error) { 121 LOGGER.log(Level.WARNING, "Exception in repository listener " + listener, error); 122 } 123 124 @Override 125 public void artifactDeployed(RepositoryEvent event) { 126 requireNonNull(event, "event cannot be null"); 127 for (RepositoryListener listener : listeners) { 128 try { 129 listener.artifactDeployed(event); 130 } catch (RuntimeException e) { 131 handleError(event, listener, e); 132 } 133 } 134 } 135 136 @Override 137 public void artifactDeploying(RepositoryEvent event) { 138 requireNonNull(event, "event cannot be null"); 139 for (RepositoryListener listener : listeners) { 140 try { 141 listener.artifactDeploying(event); 142 } catch (RuntimeException e) { 143 handleError(event, listener, e); 144 } 145 } 146 } 147 148 @Override 149 public void artifactDescriptorInvalid(RepositoryEvent event) { 150 requireNonNull(event, "event cannot be null"); 151 for (RepositoryListener listener : listeners) { 152 try { 153 listener.artifactDescriptorInvalid(event); 154 } catch (RuntimeException e) { 155 handleError(event, listener, e); 156 } 157 } 158 } 159 160 @Override 161 public void artifactDescriptorMissing(RepositoryEvent event) { 162 requireNonNull(event, "event cannot be null"); 163 for (RepositoryListener listener : listeners) { 164 try { 165 listener.artifactDescriptorMissing(event); 166 } catch (RuntimeException e) { 167 handleError(event, listener, e); 168 } 169 } 170 } 171 172 @Override 173 public void artifactDownloaded(RepositoryEvent event) { 174 requireNonNull(event, "event cannot be null"); 175 for (RepositoryListener listener : listeners) { 176 try { 177 listener.artifactDownloaded(event); 178 } catch (RuntimeException e) { 179 handleError(event, listener, e); 180 } 181 } 182 } 183 184 @Override 185 public void artifactDownloading(RepositoryEvent event) { 186 requireNonNull(event, "event cannot be null"); 187 for (RepositoryListener listener : listeners) { 188 try { 189 listener.artifactDownloading(event); 190 } catch (RuntimeException e) { 191 handleError(event, listener, e); 192 } 193 } 194 } 195 196 @Override 197 public void artifactInstalled(RepositoryEvent event) { 198 requireNonNull(event, "event cannot be null"); 199 for (RepositoryListener listener : listeners) { 200 try { 201 listener.artifactInstalled(event); 202 } catch (RuntimeException e) { 203 handleError(event, listener, e); 204 } 205 } 206 } 207 208 @Override 209 public void artifactInstalling(RepositoryEvent event) { 210 requireNonNull(event, "event cannot be null"); 211 for (RepositoryListener listener : listeners) { 212 try { 213 listener.artifactInstalling(event); 214 } catch (RuntimeException e) { 215 handleError(event, listener, e); 216 } 217 } 218 } 219 220 @Override 221 public void artifactResolved(RepositoryEvent event) { 222 requireNonNull(event, "event cannot be null"); 223 for (RepositoryListener listener : listeners) { 224 try { 225 listener.artifactResolved(event); 226 } catch (RuntimeException e) { 227 handleError(event, listener, e); 228 } 229 } 230 } 231 232 @Override 233 public void artifactResolving(RepositoryEvent event) { 234 requireNonNull(event, "event cannot be null"); 235 for (RepositoryListener listener : listeners) { 236 try { 237 listener.artifactResolving(event); 238 } catch (RuntimeException e) { 239 handleError(event, listener, e); 240 } 241 } 242 } 243 244 @Override 245 public void metadataDeployed(RepositoryEvent event) { 246 requireNonNull(event, "event cannot be null"); 247 for (RepositoryListener listener : listeners) { 248 try { 249 listener.metadataDeployed(event); 250 } catch (RuntimeException e) { 251 handleError(event, listener, e); 252 } 253 } 254 } 255 256 @Override 257 public void metadataDeploying(RepositoryEvent event) { 258 requireNonNull(event, "event cannot be null"); 259 for (RepositoryListener listener : listeners) { 260 try { 261 listener.metadataDeploying(event); 262 } catch (RuntimeException e) { 263 handleError(event, listener, e); 264 } 265 } 266 } 267 268 @Override 269 public void metadataDownloaded(RepositoryEvent event) { 270 requireNonNull(event, "event cannot be null"); 271 for (RepositoryListener listener : listeners) { 272 try { 273 listener.metadataDownloaded(event); 274 } catch (RuntimeException e) { 275 handleError(event, listener, e); 276 } 277 } 278 } 279 280 @Override 281 public void metadataDownloading(RepositoryEvent event) { 282 requireNonNull(event, "event cannot be null"); 283 for (RepositoryListener listener : listeners) { 284 try { 285 listener.metadataDownloading(event); 286 } catch (RuntimeException e) { 287 handleError(event, listener, e); 288 } 289 } 290 } 291 292 @Override 293 public void metadataInstalled(RepositoryEvent event) { 294 requireNonNull(event, "event cannot be null"); 295 for (RepositoryListener listener : listeners) { 296 try { 297 listener.metadataInstalled(event); 298 } catch (RuntimeException e) { 299 handleError(event, listener, e); 300 } 301 } 302 } 303 304 @Override 305 public void metadataInstalling(RepositoryEvent event) { 306 requireNonNull(event, "event cannot be null"); 307 for (RepositoryListener listener : listeners) { 308 try { 309 listener.metadataInstalling(event); 310 } catch (RuntimeException e) { 311 handleError(event, listener, e); 312 } 313 } 314 } 315 316 @Override 317 public void metadataInvalid(RepositoryEvent event) { 318 requireNonNull(event, "event cannot be null"); 319 for (RepositoryListener listener : listeners) { 320 try { 321 listener.metadataInvalid(event); 322 } catch (RuntimeException e) { 323 handleError(event, listener, e); 324 } 325 } 326 } 327 328 @Override 329 public void metadataResolved(RepositoryEvent event) { 330 requireNonNull(event, "event cannot be null"); 331 for (RepositoryListener listener : listeners) { 332 try { 333 listener.metadataResolved(event); 334 } catch (RuntimeException e) { 335 handleError(event, listener, e); 336 } 337 } 338 } 339 340 @Override 341 public void metadataResolving(RepositoryEvent event) { 342 requireNonNull(event, "event cannot be null"); 343 for (RepositoryListener listener : listeners) { 344 try { 345 listener.metadataResolving(event); 346 } catch (RuntimeException e) { 347 handleError(event, listener, e); 348 } 349 } 350 } 351}