/*
* Copyright (C) 2013 Red Hat, Inc. and/or its affiliates.
*
* 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 org.jboss.errai.ioc.support.bus.client;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jboss.errai.bus.client.ErraiBus;
import org.jboss.errai.bus.client.api.BusErrorCallback;
import org.jboss.errai.bus.client.api.messaging.Message;
import org.jboss.errai.bus.client.api.base.DefaultErrorCallback;
import org.jboss.errai.bus.client.api.builder.RemoteCallSendable;
import org.jboss.errai.common.client.api.BatchCaller;
import org.jboss.errai.common.client.api.ErrorCallback;
import org.jboss.errai.common.client.api.RemoteCallback;
import org.jboss.errai.common.client.framework.RemoteServiceProxyFactory;
import org.jboss.errai.common.client.framework.RpcBatch;
import org.jboss.errai.common.client.framework.RpcStub;
import org.jboss.errai.ioc.client.api.IOCProvider;
/**
* {@link IOCProvider} to make {@link BatchCaller} instances injectable.
*
* @author Christian Sadilek <csadilek@redhat.com>
*/
@IOCProvider
@Singleton
@SuppressWarnings({"rawtypes", "unchecked"})
public class BatchCallerProvider implements Provider<BatchCaller> {
private static final RemoteServiceProxyFactory factory = new RemoteServiceProxyFactory();
@Override
public BatchCaller get() {
return new BatchCaller() {
private RpcBatchImpl batch = new RpcBatchImpl();
@Override
public <T> T call(RemoteCallback<?> callback, Class<T> remoteService) {
return call(callback, null, remoteService);
}
@Override
public <T> T call(final RemoteCallback<?> callback, final ErrorCallback<?> errorCallback, final Class<T> remoteService) {
final T proxy = factory.getRemoteProxy(remoteService);
((RpcStub) proxy).setRemoteCallback(new BatchRemoteCallback(batch, callback));
((RpcStub) proxy).setErrorCallback(new BatchErrorCallback(batch, errorCallback));
((RpcStub) proxy).setBatch(batch);
return proxy;
}
@Override
public void sendBatch() {
batch.flush();
batch = new RpcBatchImpl();
}
@Override
public void sendBatch(RemoteCallback<Void> callback) {
batch.successCallback = callback;
sendBatch();
}
@Override
public void sendBatch(ErrorCallback<?> errorCallback) {
batch.errorCallback = errorCallback;
sendBatch();
}
@Override
public void sendBatch(RemoteCallback<Void> callback, ErrorCallback<?> errorCallback) {
batch.successCallback = callback;
batch.errorCallback = errorCallback;
sendBatch();
}
};
}
private class RpcBatchImpl implements RpcBatch<RemoteCallSendable> {
private final List<RemoteCallSendable> queuedRequests = new ArrayList<RemoteCallSendable>();
private final List<RemoteCallback<?>> pendingCallbacks = new ArrayList<RemoteCallback<?>>();
private RemoteCallback<Void> successCallback;
private ErrorCallback errorCallback;
@Override
public void addRequest(RemoteCallSendable request) {
queuedRequests.add(request);
}
@Override
public void flush() {
for (RemoteCallSendable request : queuedRequests) {
request.sendNowWith(ErraiBus.get());
}
queuedRequests.clear();
}
public void onSuccess(RemoteCallback<?> callback) {
pendingCallbacks.remove(callback);
if (pendingCallbacks.isEmpty() && successCallback != null) {
successCallback.callback(null);
}
}
public void onError(Message m, Throwable t) {
if (errorCallback != null) {
errorCallback.error(m, t);
}
}
}
private class BatchRemoteCallback<R> implements RemoteCallback<R> {
private final RpcBatchImpl batch;
private final RemoteCallback<R> remoteCallback;
public BatchRemoteCallback(RpcBatchImpl batch, RemoteCallback<R> remoteCallback) {
this.batch = batch;
this.remoteCallback = remoteCallback;
this.batch.pendingCallbacks.add(remoteCallback);
}
@Override
public void callback(R response) {
remoteCallback.callback(response);
batch.onSuccess(remoteCallback);
}
}
private class BatchErrorCallback implements BusErrorCallback {
private final RpcBatchImpl batch;
private final ErrorCallback errorCallback;
public BatchErrorCallback(RpcBatchImpl batch, ErrorCallback errorCallback) {
this.batch = batch;
this.errorCallback = errorCallback;
}
@Override
public boolean error(Message message, Throwable throwable) {
if (errorCallback != null) {
errorCallback.error(message, throwable);
}
else {
DefaultErrorCallback.INSTANCE.error(message, throwable);
}
batch.onError(message, throwable);
return false;
}
}
}