/* * Copyright (c) 2012 European Synchrotron Radiation Facility, * Diamond Light Source Ltd. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package uk.ac.diamond.gwt.rf.queue.client.core; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import uk.ac.diamond.gwt.rf.queue.shared.RequestFactoryQueue; import com.google.gwt.http.client.Request; import com.google.gwt.http.client.RequestBuilder; import com.google.gwt.http.client.RequestCallback; import com.google.gwt.http.client.RequestException; import com.google.gwt.http.client.Response; import com.google.web.bindery.requestfactory.gwt.client.DefaultRequestTransport; import com.google.web.bindery.requestfactory.shared.RequestTransport; import com.google.web.bindery.requestfactory.shared.ServerFailure; /** * EXPERT - A RequestTransport capable of batching semi independent FR Requests * across a single HTTP Request */ public class QosRequestTransport extends DefaultRequestTransport { private static final Logger wireLogger = Logger.getLogger("UasWireActivityLogger"); static RequestTransport.TransportReceiver CAPTURE = new RequestTransport.TransportReceiver() { @Override public void onTransportSuccess(String payload) { } @Override public void onTransportFailure(ServerFailure failure) { } }; /** * (Request) Payload and Receiver */ static class BatchedRequest { String payload; RequestTransport.TransportReceiver receiver; RequestTransport.TransportReceiver receiverForEntry; } private List<BatchedRequest> batch; private PipeInput defaultSource; private RequestTransport.TransportReceiver nextReceiverForEntry; private AuthFailureDetector authFailureDetector; public PipeInput getDefaultSource() { return defaultSource; } public void setDefaultSource(PipeInput defaultSource) { this.defaultSource = defaultSource; } void startBatch() { batch = new ArrayList<BatchedRequest>(); } List<BatchedRequest> flushBatch() { StringBuilder payload2 = new StringBuilder(); for (BatchedRequest request : batch) { if (payload2.length() > 0) { payload2.append(RequestFactoryQueue.DELIMITER); } payload2.append(request.payload); } sendBatch(payload2.toString(), batch); List<BatchedRequest> orig = batch; batch = null; return orig; } @Override public void send(java.lang.String payload, RequestTransport.TransportReceiver receiver) { if (nextReceiverForEntry != null) { BatchedRequest request = new BatchedRequest(); request.payload = payload; request.receiver = receiver; request.receiverForEntry = nextReceiverForEntry; if (batch != null) { // is just a normal explicit batch request batch.add(request); } if (batch == null) { // is an implicit batch to just capture batch = new ArrayList<BatchedRequest>(); batch.add(request); } nextReceiverForEntry = null; } else { // no receiver for QosEntry so direct request defaultSource.add(new TransportEntry(payload, receiver)); } } private void sendBatch(String payload, List<BatchedRequest> currentBatch) { // XXX use super.send? RequestBuilder builder = createRequestBuilder(); configureRequestBuilder(builder); builder.setRequestData(payload); builder.setCallback(createRequestCallbackBatch(currentBatch)); try { wireLogger.finest("Sending fire request"); builder.send(); } catch (RequestException e) { wireLogger.log(Level.SEVERE, " (" + e.getMessage() + ")", e); } } protected RequestCallback createRequestCallbackBatch(final List<BatchedRequest> currentBatch) { return new RequestCallback() { @Override public void onError(Request request, Throwable exception) { wireLogger.log(Level.WARNING, "onError.SERVER_ERROR", exception); for (BatchedRequest batchedRequest : currentBatch) { batchedRequest.receiverForEntry.onTransportFailure(new ServerFailure(exception.getMessage())); try { // XXX not do this till retry fails? batchedRequest.receiver.onTransportFailure(new ServerFailure(exception.getMessage())); } catch (Throwable th) { wireLogger.log(Level.SEVERE, "RF Receiver failed", th); } } } @Override public void onResponseReceived(Request request, Response response) { wireLogger.finest("Response received"); if (authFailureDetector != null && authFailureDetector.isLoginRedirect(response)) { for (BatchedRequest batchedRequest : currentBatch) { // XXX only once per batch? if (batchedRequest.receiverForEntry != null) { batchedRequest.receiverForEntry.onTransportFailure(new ServerFailure("AUTH")); } } } else if (Response.SC_OK == response.getStatusCode()) { String text = response.getText(); String[] split = text.split(RequestFactoryQueue.DELIMITER); int i = 0; for (String x : split) { if (currentBatch.get(i).receiverForEntry != null) { currentBatch.get(i).receiverForEntry.onTransportSuccess(x); } try { currentBatch.get(i).receiver.onTransportSuccess(x); } catch (Throwable th) { // do not want these failures to leave Qos hanging wireLogger.log(Level.SEVERE, "RF Receiver failed", th); } // XXX only once per batch? i++; } } else { String message = "onResponseReceived.SERVER_ERROR" + " " + response.getStatusCode() + " " + response.getText(); wireLogger.warning(message); for (BatchedRequest batchedRequest : currentBatch) { batchedRequest.receiverForEntry.onTransportFailure(new ServerFailure(message)); } } } }; } public void setNextReceiverForEntry(RequestTransport.TransportReceiver treceiver2) { nextReceiverForEntry = treceiver2; } public AuthFailureDetector getAuthFailureDetector() { return authFailureDetector; } public void setAuthFailureDetector(AuthFailureDetector p) { this.authFailureDetector = p; } }