001/* Copyright 2011-2013 the original author or authors:
002 *
003 *    Marc Palmer (marc@grailsrocks.com)
004 *    Stéphane Maldini (smaldini@vmware.com)
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * 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, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.grails.plugin.platform.events;
019
020import grails.events.EventException;
021import groovy.lang.Closure;
022
023import java.io.Serializable;
024import java.util.ArrayList;
025import java.util.Collection;
026import java.util.List;
027import java.util.concurrent.ExecutionException;
028import java.util.concurrent.Future;
029import java.util.concurrent.TimeUnit;
030import java.util.concurrent.TimeoutException;
031
032/**
033 * @author Stephane Maldini <smaldini@vmware.com>
034 * @version 1.0
035 * @file
036 * @date 30/12/11
037 * @section DESCRIPTION
038 * <p/>
039 * [Does stuff]
040 */
041public class EventReply implements Serializable, Future<Object> {
042
043    private static final long serialVersionUID = 1;
044
045    private Future<?> futureReply;
046    private List<Object> values;
047    private Object value;
048    private int receivers;
049    private boolean futureReplyLoaded = false;
050    @SuppressWarnings("rawtypes") private Closure onError;
051
052    @SuppressWarnings("rawtypes")
053    public void setOnError(Closure onError) {
054        this.onError = onError;
055    }
056
057    @SuppressWarnings("rawtypes")
058    public Closure getOnError() {
059        return onError;
060    }
061
062    public EventReply(Object val, int receivers) {
063        this.receivers = receivers;
064        initValues(val);
065    }
066
067    protected void initValues(Object val) {
068        this.values = new ArrayList<Object>();
069
070        if (receivers > 1 && val instanceof Collection) {
071            this.values.addAll((Collection<?>) val);
072            this.value = values.get(0);
073        } else if(receivers != 0 || val != null) {
074            this.value = val;
075            this.values.add(this.value);
076        }
077        this.futureReplyLoaded = true;
078    }
079
080    public EventReply(Future<?> future, int receivers) {
081        this.receivers = receivers;
082        this.futureReply = future;
083    }
084
085    protected void addValue(Object v) {
086        values.add(v);
087    }
088
089    public List<Object> getValues() throws Throwable {
090        if (!futureReplyLoaded) {
091            get();
092        }
093        throwError();
094        return values;
095    }
096
097    public Object getValue() throws Throwable{
098        if (!futureReplyLoaded) {
099            get();
100        }
101        throwError();
102        return value;
103    }
104
105    public boolean cancel(){
106        return cancel(true);
107    }
108
109    public boolean cancel(boolean b) {
110        return futureReply == null || futureReply.cancel(b);
111    }
112
113    public boolean isCancelled() {
114        return futureReply != null && futureReply.isCancelled();
115    }
116
117    public boolean isDone() {
118        return futureReply == null || futureReply.isDone();
119    }
120
121    public boolean isSuccess() {
122        return isDone() && !hasErrors();
123    }
124
125    public List<Throwable> getErrors() {
126        List<Throwable> ex = new ArrayList<Throwable>();
127        if (values != null) {
128            for (Object v : values) {
129                if (v != null && Throwable.class.isAssignableFrom(v.getClass())) {
130                    ex.add((Throwable) v);
131                }
132            }
133        }
134
135        return ex;
136    }
137
138    public boolean hasErrors() {
139        for (Object v : values) {
140            if (v != null && Throwable.class.isAssignableFrom(v.getClass())) {
141                return true;
142            }
143        }
144        return false;
145    }
146
147    public void throwError() throws Throwable{
148        if(hasErrors()){
149            if(onError != null){
150                onError.call(this);
151            }else{
152                throw new EventException(getErrors().get(0));
153            }
154        }
155    }
156
157    public int size() throws Throwable {
158        get();
159        throwError();
160        return receivers;
161    }
162
163    protected void setReceivers(int receivers) {
164        this.receivers = receivers;
165    }
166
167    public EventReply waitFor() throws Throwable {
168        get();
169        throwError();
170        return this;
171    }
172
173    public EventReply waitFor(long l) throws Throwable {
174        get(l, TimeUnit.MILLISECONDS);
175        throwError();
176        return this;
177    }
178
179    public Object get() throws InterruptedException, ExecutionException {
180        Object val = futureReply == null ? value : futureReply.get();
181        if (!futureReplyLoaded) {
182            initValues(val);
183        }
184        return val;
185    }
186
187    public Object get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
188        Object val = futureReply == null ? value : futureReply.get(l, timeUnit);
189        if (!futureReplyLoaded) {
190            initValues(val);
191        }
192        return val;
193    }
194
195}