org.nuxeo.client.api.objects.NuxeoEntity.java Source code

Java tutorial

Introduction

Here is the source code for org.nuxeo.client.api.objects.NuxeoEntity.java

Source

/*
 * (C) Copyright 2016 Nuxeo SA (http://nuxeo.com/) and others.
 *
 * 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.
 *
 * Contributors:
 *         Vladimir Pasquier <vpasquier@nuxeo.com>
 */
package org.nuxeo.client.api.objects;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.logging.log4j.util.Strings;
import org.nuxeo.client.api.ConstantsV1;
import org.nuxeo.client.api.NuxeoClient;
import org.nuxeo.client.api.objects.blob.Blob;
import org.nuxeo.client.api.objects.blob.Blobs;
import org.nuxeo.client.internals.spi.NuxeoClientException;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import okhttp3.Headers;
import okhttp3.Request;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

/**
 * @since 0.1
 */
public abstract class NuxeoEntity<T> {

    @JsonProperty("entity-type")
    protected final String entityType;

    @JsonProperty("repository")
    protected String repositoryName;

    @JsonIgnore
    protected boolean refreshCache = false;

    @JsonIgnore
    protected NuxeoClient nuxeoClient;

    @JsonIgnore
    protected Object api;

    @JsonIgnore
    protected Class<Object> apiClass;

    /**
     * For Serialization purpose.
     */
    public NuxeoEntity(String entityType) {
        this.entityType = entityType;
    }

    /**
     * The constructor to use.
     */
    public NuxeoEntity(String entityType, NuxeoClient nuxeoClient, Class apiClass) {
        this.entityType = entityType;
        this.nuxeoClient = nuxeoClient;
        this.apiClass = apiClass;
    }

    public String getEntityType() {
        return entityType;
    }

    /**
     * Handle invocation of API Methods Asynchronously. Results will be returned in the given callback.
     */
    public void execute(Callback<T> callback, Object... parametersArray) {
        if (api == null) {
            api = nuxeoClient.getRetrofit().create(apiClass);
        }
        if (nuxeoClient == null) {
            throw new NuxeoClientException("You should pass to your Nuxeo object the client instance");
        }
        String method = getCurrentMethodName();
        Call<T> methodResult = getCall(api, method, parametersArray);
        methodResult.enqueue(callback);
    }

    /**
     * Handle cache and invocation of API methods.
     *
     * @return the response as business objects.
     */
    protected Object getResponse(Object... parametersArray) {
        if (nuxeoClient == null) {
            throw new NuxeoClientException("You should pass to your Nuxeo object the client instance");
        }
        if (api == null) {
            api = nuxeoClient.getRetrofit().create(apiClass);
        }
        String method = getCurrentMethodName();
        Call<?> methodResult = getCall(api, method, parametersArray);
        String cacheKey = Strings.EMPTY;
        if (nuxeoClient.isCacheEnabled()) {
            if (refreshCache) {
                this.refreshCache = false;
                nuxeoClient.getNuxeoCache().invalidateAll();
            } else {
                cacheKey = computeCacheKey(methodResult);
                NuxeoEntity result = (NuxeoEntity) nuxeoClient.getNuxeoCache().getBody(cacheKey);
                if (result != null) {
                    return result;
                }
            }
        }
        try {
            Response<?> response = methodResult.execute();
            // For redirect 308 -> the response should be success
            if (!response.isSuccessful() && response.code() != 308) {
                NuxeoClientException nuxeoClientException;
                String errorBody = response.errorBody().string();
                if (Strings.EMPTY.equals(errorBody)) {
                    nuxeoClientException = new NuxeoClientException(response.code(), response.message());
                } else if (!ConstantsV1.APPLICATION_JSON.equals(response.raw().body().contentType())) {
                    nuxeoClientException = new NuxeoClientException(response.code(), errorBody);
                } else {
                    nuxeoClientException = nuxeoClient.getConverterFactory().readJSON(errorBody,
                            NuxeoClientException.class);
                }
                throw nuxeoClientException;
            }
            if (nuxeoClient.isCacheEnabled()) {
                nuxeoClient.getNuxeoCache().put(cacheKey, response);
            }
            Object body = response.body();
            if (body instanceof ResponseBody) {
                return body;
            } else if (body == null) {
                if (response.code() == 204) {
                    if (ConstantsV1.APPLICATION_NUXEO_EMPTY_LIST.equals(response.headers().get("Content-Type"))) {
                        return new Blobs();
                    }
                    return null;
                }
                return response;
            } else {
                return reconnectObject(body, response.headers(), api, nuxeoClient);
            }
        } catch (IOException reason) {
            throw new NuxeoClientException(reason);
        }
    }

    /**
     * Compute the cache key with request
     */
    protected String computeCacheKey(Call<?> methodResult) {
        Request originalRequest = methodResult.request();
        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance(ConstantsV1.MD_5);
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
        digest.update((originalRequest.toString() + originalRequest.headers().toString()).getBytes());
        byte messageDigest[] = digest.digest();
        StringBuilder hexString = new StringBuilder();
        for (byte msg : messageDigest) {
            hexString.append(Integer.toHexString(0xFF & msg));
        }
        return hexString.toString();
    }

    /**
     * Invoking the method of each class "API"
     */
    protected Call<T> getCall(Object api, String methodName, Object... parametersArray) {
        try {
            Method[] methods = api.getClass().getInterfaces()[0].getMethods();
            if (repositoryName != null) {
                int len = parametersArray.length;
                parametersArray = Arrays.copyOf(parametersArray, len + 1);
                parametersArray[len] = repositoryName;
            }
            Method method = null;
            for (Method currentMethod : methods) {
                if (currentMethod.getName().equals(methodName)) {
                    if (currentMethod.getParameterTypes().length == parametersArray.length) {
                        method = currentMethod;
                        break;
                    }
                }
            }
            if (method == null) {
                throw new NuxeoClientException(String.format(
                        "No method found for API %s and method name '%s'. Check method name and parameters.",
                        apiClass, methodName));
            }
            return (Call<T>) method.invoke(api, parametersArray);
        } catch (IllegalArgumentException | IllegalAccessException reason) {
            throw new NuxeoClientException(String.format(
                    "An issue has occured in the method found for API %s and method name '%s'. Check method and parameters types.",
                    apiClass, methodName), reason);
        } catch (InvocationTargetException reason) {
            throw new NuxeoClientException(reason.getTargetException().getMessage(), reason);
        }
    }

    protected String getCurrentMethodName() {
        StackTraceElement stackTraceElements[] = (new Throwable()).getStackTrace();
        return stackTraceElements[2].getMethodName();
    }

    protected Object reconnectObject(Object entity, Headers headers, Object api, NuxeoClient nuxeoClient) {
        if (entity instanceof NuxeoEntity) {
            ((NuxeoEntity) entity).nuxeoClient = nuxeoClient;
            ((NuxeoEntity) entity).api = api;
            ((NuxeoEntity) entity).apiClass = apiClass;
            if (entity instanceof Documents) {
                for (Document doc : ((Documents) entity).getDocuments()) {
                    doc.nuxeoClient = nuxeoClient;
                    doc.api = api;
                    doc.apiClass = apiClass;
                }
            } else if (entity instanceof Blobs) {
                for (Blob blob : ((Blobs) entity).getBlobs()) {
                    blob.nuxeoClient = nuxeoClient;
                    blob.api = api;
                    blob.apiClass = apiClass;
                }
            } else if (entity instanceof Blob) {
                String contentDisposition = headers.get("Content-Disposition");
                if (contentDisposition != null) {
                    String fileName = contentDisposition.replaceFirst(".*filename\\*?=(UTF-8'')?(.*)", "$2");
                    try {
                        fileName = URLDecoder.decode(fileName, "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        // May not happen
                    }
                    ((Blob) entity).setFileName(fileName);
                }
            }
            return entity;
        } else if (entity instanceof List<?>) {
            List<NuxeoEntity> entities = new ArrayList<>();
            List<?> l = (List<?>) entity;
            for (Object item : l) {
                if (item instanceof NuxeoEntity) {
                    ((NuxeoEntity) item).nuxeoClient = nuxeoClient;
                    ((NuxeoEntity) item).api = api;
                    ((NuxeoEntity) item).apiClass = apiClass;
                    entities.add((NuxeoEntity) item);
                }
            }
            return entities;
        }
        return entity;
    }
}