| /* | |
| * Copyright 2011 Google Inc. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not | |
| * use this file except in compliance with the License. You may obtain a copy of | |
| * the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
| * License for the specific language governing permissions and limitations under | |
| * the License. | |
| */ | |
| package com.google.web.bindery.requestfactory.shared; | |
| import com.google.web.bindery.event.shared.UmbrellaException; | |
| import java.util.ArrayList; | |
| import java.util.LinkedHashSet; | |
| import java.util.List; | |
| import java.util.Set; | |
| import javax.validation.ConstraintViolation; | |
| /** | |
| * A FanoutReceiver will forward its callbacks to zero or more other Receivers. | |
| * Any exceptions thrown by the queued Receivers will be re-thrown as an | |
| * {@link UmbrellaException} after all Receivers have been invoked. | |
| * | |
| * @param <T> the type of data being received | |
| */ | |
| public class FanoutReceiver<T> extends Receiver<T> { | |
| private List<Receiver<? super T>> toCall; | |
| private Set<Throwable> toThrow; | |
| /** | |
| * Register a receiver to be called by the fanout. | |
| * | |
| * @throws IllegalArgumentException if {@code receiver} is {@code null} | |
| */ | |
| public void add(Receiver<? super T> receiver) { | |
| if (receiver == null) { | |
| throw new IllegalArgumentException(); | |
| } | |
| if (toCall == null) { | |
| toCall = new ArrayList<Receiver<? super T>>(); | |
| } | |
| toCall.add(receiver); | |
| } | |
| @Override | |
| public void onConstraintViolation(Set<ConstraintViolation<?>> violations) { | |
| try { | |
| if (toCall != null) { | |
| for (Receiver<? super T> r : toCall) { | |
| try { | |
| r.onConstraintViolation(violations); | |
| } catch (Throwable t) { | |
| onUncaughtThrowable(t); | |
| } | |
| } | |
| } | |
| } finally { | |
| finish(); | |
| } | |
| } | |
| @Override | |
| public void onFailure(ServerFailure error) { | |
| try { | |
| if (toCall != null) { | |
| for (Receiver<? super T> r : toCall) { | |
| try { | |
| r.onFailure(error); | |
| } catch (Throwable t) { | |
| onUncaughtThrowable(t); | |
| } | |
| } | |
| } | |
| } finally { | |
| finish(); | |
| } | |
| } | |
| @Override | |
| public void onSuccess(T response) { | |
| try { | |
| if (toCall != null) { | |
| for (Receiver<? super T> r : toCall) { | |
| try { | |
| r.onSuccess(response); | |
| } catch (Throwable t) { | |
| onUncaughtThrowable(t); | |
| } | |
| } | |
| } | |
| } finally { | |
| finish(); | |
| } | |
| } | |
| @Deprecated | |
| @Override | |
| public void onViolation(Set<Violation> errors) { | |
| try { | |
| if (toCall != null) { | |
| for (Receiver<? super T> r : toCall) { | |
| try { | |
| r.onViolation(errors); | |
| } catch (Throwable t) { | |
| onUncaughtThrowable(t); | |
| } | |
| } | |
| } | |
| } finally { | |
| finish(); | |
| } | |
| } | |
| /** | |
| * Called after all Receivers have been executed. | |
| */ | |
| protected void finish() { | |
| if (toThrow != null) { | |
| // Reset if the user wants to re-fire the Request | |
| Set<Throwable> causes = toThrow; | |
| toThrow = null; | |
| throw new UmbrellaException(causes); | |
| } | |
| } | |
| /** | |
| * Subclasses may override this method to alter how the FanoutReceiver | |
| * collects exceptions that escape from the queued Receivers. | |
| */ | |
| protected void onUncaughtThrowable(Throwable t) { | |
| if (toThrow == null) { | |
| toThrow = new LinkedHashSet<Throwable>(); | |
| } | |
| toThrow.add(t); | |
| } | |
| } |