/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* 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
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.websocket.rest;
import org.eclipse.che.ide.commons.exception.UnmarshallerException;
import org.eclipse.che.ide.rest.AsyncRequestLoader;
import org.eclipse.che.ide.rest.HTTPHeader;
import org.eclipse.che.ide.rest.HTTPStatus;
import org.eclipse.che.ide.rest.RequestStatusHandler;
import org.eclipse.che.ide.websocket.Message;
import org.eclipse.che.ide.websocket.MessageBuilder;
import org.eclipse.che.ide.websocket.rest.exceptions.ServerException;
import org.eclipse.che.ide.websocket.rest.exceptions.UnauthorizedException;
import com.google.gwt.http.client.Response;
import java.util.List;
/**
* Callback to receive a {@link Message}.
*
* @author Artem Zatsarynnyi
*/
public abstract class RequestCallback<T> {
// http code 207 is "Multi-Status"
// IE misinterpreting HTTP status code 204 as 1223 (http://www.mail-archive.com/jquery-en@googlegroups.com/msg13093.html)
private static final int[] DEFAULT_SUCCESS_CODES = {Response.SC_OK, Response.SC_CREATED, Response.SC_NO_CONTENT, 207, 1223};
/** Deserializer for the body of the {@link Message}. */
private final Unmarshallable<T> unmarshaller;
/** Status codes of the successful responses. */
private int[] successCodes;
/** An object deserialized from the response. */
private T payload;
/** Handler to show an execution state of operation. */
private RequestStatusHandler statusHandler;
/** Loader to show while request is calling. */
private AsyncRequestLoader loader;
public RequestCallback() {
this.successCodes = DEFAULT_SUCCESS_CODES;
this.unmarshaller = null;
}
/**
* Constructor retrieves unmarshaller with initialized (this is important!) object.
* When response comes then callback calls {@link Unmarshallable#unmarshal(com.codenvy.ide.websocket.Message)}
* which populates the object.
*
* @param unmarshaller
* {@link Unmarshallable}
*/
public RequestCallback(Unmarshallable<T> unmarshaller) {
this.successCodes = DEFAULT_SUCCESS_CODES;
this.unmarshaller = unmarshaller;
}
/**
* Perform actions when response message was received.
*
* @param message
* message
*/
public void onReply(Message message) {
if (loader != null) {
loader.hide();
}
final String uuid = message.getStringField(MessageBuilder.UUID_FIELD);
if (message.getResponseCode() == HTTPStatus.UNAUTHORIZED) {
UnauthorizedException exception = new UnauthorizedException(message);
if (statusHandler != null) {
statusHandler.requestError(uuid, exception);
}
onFailure(exception);
return;
}
if (isSuccessful(message)) {
try {
if (unmarshaller != null) {
unmarshaller.unmarshal(message);
payload = unmarshaller.getPayload();
}
if (statusHandler != null) {
statusHandler.requestFinished(uuid);
}
onSuccess(payload);
} catch (UnmarshallerException e) {
if (statusHandler != null) {
statusHandler.requestError(uuid, e);
}
onFailure(e);
}
} else {
ServerException exception = new ServerException(message);
if (statusHandler != null) {
statusHandler.requestError(uuid, exception);
}
onFailure(exception);
}
}
/**
* Is response successful?
*
* @param response
* {@link Message}
* @return <code>true</code> if response is successful and <code>false</code> if response is not successful
*/
protected final boolean isSuccessful(Message response) {
if (successCodes == null) {
successCodes = DEFAULT_SUCCESS_CODES;
}
List<Pair> headers = response.getHeaders().toList();
if (headers != null) {
for (Pair header : headers) {
if (HTTPHeader.JAXRS_BODY_PROVIDED.equals(header.getName()) && "Authentication-required".equals(header.getValue())) {
return false;
}
}
}
for (int code : successCodes)
if (response.getResponseCode() == code)
return true;
return false;
}
/**
* Set the array of successful HTTP status codes.
*
* @param successCodes
* the successCodes to set
*/
public void setSuccessCodes(int[] successCodes) {
this.successCodes = successCodes;
}
/** Get handler to show an execution state of request. */
public final RequestStatusHandler getStatusHandler() {
return statusHandler;
}
/**
* Set handler to show an execution state of request.
*
* @param handler
* status handler
*/
public final void setStatusHandler(RequestStatusHandler handler) {
this.statusHandler = handler;
}
/** Get the loader to show while request is calling. */
public final AsyncRequestLoader getLoader() {
return loader;
}
/**
* Set the loader to show while request is calling.
*
* @param loader
* loader to show while request is calling
*/
public final void setLoader(AsyncRequestLoader loader) {
this.loader = loader;
}
/**
* Invokes if response is successfully received and
* response status code is in set of success codes.
*
* @param result
*/
protected abstract void onSuccess(T result);
/**
* Invokes if an error received from the server.
*
* @param exception
* caused failure
*/
protected abstract void onFailure(Throwable exception);
}