blob: 1176bd9aace6370c56214d0d4805d1e825e754db [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.apache.eagle.common.rest;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.eagle.common.function.ThrowableConsumer;
import org.apache.eagle.common.function.ThrowableSupplier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.function.Supplier;
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class RESTResponse<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(RESTResponse.class);
@JsonProperty
private boolean success = false;
@JsonProperty
private String message;
@JsonProperty
private String exception;
@JsonProperty
private T data;
public RESTResponse() {
}
public RESTResponse(Throwable throwable) {
if (throwable.getMessage() == null || throwable.getMessage().isEmpty()) {
this.setMessage(throwable.getMessage());
} else {
this.setMessage(ExceptionUtils.getMessage(throwable));
}
this.setException(ExceptionUtils.getStackTrace(throwable));
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public static <E> RestResponseBuilder<E> builder() {
return new RestResponseBuilder<>();
}
public static <E> RestResponseBuilder<E> of(E data) {
return RESTResponse.<E>builder().data(data);
}
public static <E> RestResponseBuilder<E> of(Consumer<RestResponseBuilder<E>> func) {
return RESTResponse.<E>builder().of(func);
}
public static <E> RestResponseBuilder<E> of(Supplier<E> func) {
return RESTResponse.<E>builder().of(func);
}
public static <E> RestResponseBuilder<E> async(ThrowableSupplier<E, Exception> func) {
return RESTResponse.<E>builder().async(func);
}
public static <E> RestResponseBuilder<E> async(ThrowableConsumer<RestResponseBuilder<E>, Exception> func) {
return RESTResponse.<E>builder().async(func);
}
public String getException() {
return exception;
}
public void setThrowable(Throwable exception) {
this.setException(ExceptionUtils.getStackTrace(exception));
}
public void setException(String exception) {
this.exception = exception;
}
public static class RestResponseBuilder<E> {
private RESTResponse current = new RESTResponse();
private Response.Status status = Response.Status.OK;
private CompletableFuture future = null;
public RestResponseBuilder<E> success(boolean success) {
this.current.setSuccess(success);
return this;
}
public RestResponseBuilder<E> status(Response.Status status) {
this.status = status;
return this;
}
public RestResponseBuilder<E> status(boolean success, Response.Status status) {
this.success(success);
this.status(status);
return this;
}
public RestResponseBuilder<E> message(String message) {
this.current.setMessage(message);
return this;
}
public RestResponseBuilder<E> data(E data) {
this.current.setData(data);
return this;
}
public RestResponseBuilder<E> exception(Throwable exception) {
this.current.setThrowable(exception);
if (this.current.getMessage() == null) {
if (exception.getMessage() == null || exception.getMessage().isEmpty()) {
this.current.setMessage(ExceptionUtils.getMessage(exception));
} else {
this.current.setMessage(exception.getMessage());
}
}
return this;
}
public RestResponseBuilder<E> of(Consumer<RestResponseBuilder<E>> func) {
try {
this.success(true).status(Response.Status.OK);
func.accept(this);
} catch (Exception ex) {
LOGGER.error("Exception: " + ex.getMessage(), ex);
this.success(false).data(null).status(Response.Status.BAD_REQUEST).exception(ex);
raiseWebAppException(ex);
}
return this;
}
public RestResponseBuilder<E> of(Supplier<E> func) {
try {
this.success(true).status(Response.Status.OK).data(func.get());
} catch (Throwable ex) {
LOGGER.error("Exception: " + ex.getMessage(), ex);
this.success(false).status(Response.Status.BAD_REQUEST).exception(ex);
raiseWebAppException(ex);
}
return this;
}
public RestResponseBuilder<E> async(ThrowableSupplier<E, Exception> func) {
CompletableFuture future = CompletableFuture.runAsync(() -> {
try {
this.status(Response.Status.OK).success(true).data(func.get());
} catch (Throwable e) {
LOGGER.error("Exception: " + e.getMessage(), e);
this.success(false).status(Response.Status.BAD_REQUEST).exception(e);
raiseWebAppException(e);
}
});
runAsync(future);
return this;
}
public RestResponseBuilder<E> async(ThrowableConsumer<RestResponseBuilder<E>, Exception> func) {
CompletableFuture future = CompletableFuture.runAsync(() -> {
try {
func.accept(this);
this.success(true);
} catch (Throwable ex) {
LOGGER.error("Exception: " + ex.getMessage(), ex);
this.success(false).status(Response.Status.BAD_REQUEST).exception(ex);
raiseWebAppException(ex);
}
});
runAsync(future);
return this;
}
private void runAsync(Future future) {
try {
future.get();
} catch (InterruptedException ex) {
LOGGER.error("InterruptedException: " + ex.getMessage(), ex);
Thread.currentThread().interrupt();
future.cancel(true);
this.success(false).status(Response.Status.BAD_REQUEST).exception(ex.getCause());
raiseWebAppException(ex);
} catch (ExecutionException ex) {
LOGGER.error("ExecutionException: " + ex.getMessage(), ex);
this.success(false).status(Response.Status.BAD_REQUEST).exception(ex.getCause());
raiseWebAppException(ex);
}
}
private void raiseWebAppException(Throwable ex) {
throw new WebApplicationException(ex, Response.status(this.status).entity(this.current).build());
}
public RestResponseBuilder<E> then(ThrowableConsumer<RestResponseBuilder<E>, Exception> func) {
try {
func.accept(this);
} catch (Throwable ex) {
LOGGER.error("Exception: " + ex.getMessage(), ex);
this.success(false).status(Response.Status.BAD_REQUEST).exception(ex);
raiseWebAppException(ex);
}
return this;
}
public RESTResponse<E> get() {
return current;
}
public Response build() {
return Response.status(status).entity(current).type(MediaType.APPLICATION_JSON).build();
}
}
}