All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redhat.lightblue.Response Maven / Gradle / Ivy

/*
 Copyright 2013 Red Hat, Inc. and/or its affiliates.

 This file is part of lightblue.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see .
 */
package com.redhat.lightblue;

import java.util.Iterator;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.redhat.lightblue.util.Error;
import com.redhat.lightblue.util.JsonUtils;
import com.redhat.lightblue.util.MemoryMonitor;
import com.redhat.lightblue.util.MemoryMonitor.ThresholdMonitor;

/**
 * Response information from mediator APIs
 */
public class Response extends BaseResponse  {

    private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = LoggerFactory.getLogger(Response.class);

    private static final String PROPERTY_PROCESSED = "processed";
    private static final String PROPERTY_RESULT_METADATA = "resultMetadata";

    private JsonNode entityData;
    private List resultMetadata;

    private MemoryMonitor memoryMonitor = null;

    // Response has no access to CrudConstants
    public static final String ERR_RESULT_SIZE_TOO_LARGE = "crud:ResultSizeTooLarge";

    public Response(JsonNodeFactory jsonNodeFactory, OperationStatus status) {
        super(jsonNodeFactory, status);
    }

    public Response(Response r) {
        super(r);
        entityData=r.entityData;
        resultMetadata=r.resultMetadata;
    }

    public Response(BaseResponse r) {
        super(r);
    }

    /**
     * Result set size threshold is expressed in bytes. This is just an approximation, see @{link {@link JsonUtils#size(JsonNode)} for details.
     *
     * @param maxResultSetSizeB error when this threshold is breached
     * @param warnResultSetSizeB log a warning when this threshold is breached
     * @param forRequest request which resulted in this response, for logging purposes
     */
    public void setResultSizeThresholds(int maxResultSetSizeB, int warnResultSetSizeB, final Request forRequest) {
        this.memoryMonitor = new MemoryMonitor<>((jsonNode) -> JsonUtils.size(jsonNode));

        memoryMonitor.registerMonitor(new ThresholdMonitor(maxResultSetSizeB, (current, threshold, doc) -> {
            // empty data
            // returning incomplete result set could be useful, but also confusing and thus dangerous
            // the counts - matchCount, modifiedCount - are unmodified
            setEntityData(JsonNodeFactory.instance.arrayNode());
            setStatus(OperationStatus.ERROR);
            throw Error.get(ERR_RESULT_SIZE_TOO_LARGE, current+"B > "+threshold+"B");
        }));

        memoryMonitor.registerMonitor(new ThresholdMonitor(warnResultSetSizeB, (current, threshold, doc) -> {
            LOGGER.warn("crud:ResultSizeIsLarge: request={}, responseDataSizeB={}", forRequest, current);
        }));

    }

    /**
     * Returns the entity data resulting from the call.
     */
    public JsonNode getEntityData() {
        return entityData;
    }

    /**
     * Returns the entity data resulting from the call.
     */
    public void setEntityData(JsonNode node) {
        // if the node is not an array then wrap it in an array
        if (node != null && !node.isArray()) {
            ArrayNode arrayNode = new ArrayNode(jsonNodeFactory);
            arrayNode.add(node);
            entityData = arrayNode;
        } else {
            entityData = node;
        }
    }

    /**
     * Adds a document, or array of documents to the entity data
     */
    public void addEntityData(JsonNode doc) {
        if(doc!=null) {

            if (memoryMonitor != null) {
                memoryMonitor.apply(doc);
            }

            if(entityData==null) {
                entityData=JsonNodeFactory.instance.arrayNode();
            }
            if(doc instanceof ArrayNode) {
                for(Iterator itr=doc.elements();itr.hasNext();) {
                    ((ArrayNode)entityData).add(itr.next());
                }
            } else {
                ((ArrayNode)entityData).add(doc);
            }
        }
    }

    /**
     * Metadata list for documents in entityData. If there are more
     * than one documents, the entitydata and metadata indexes match.
     */
    public List getResultMetadata() {
        return resultMetadata;
    }

    public void setResultMetadata(List l) {
        resultMetadata=l;
    }

    /**
     * Returns JSON representation of this
     */
    @Override
    public JsonNode toJson() {
        ObjectNode node=(ObjectNode)super.toJson();
        if(entityData!=null) {
            node.set(PROPERTY_PROCESSED, entityData);
        }
        if(resultMetadata!=null) {
            ArrayNode arr=jsonNodeFactory.arrayNode();
            for(ResultMetadata x:resultMetadata) {
                arr.add(x==null?jsonNodeFactory.nullNode():x.toJson());
            }
            node.set(PROPERTY_RESULT_METADATA,arr);
        }
        return node;
    }

    public int getResponseDataSizeB() {
        if (memoryMonitor != null) {
            return memoryMonitor.getDataSizeB();
        } else {
            return 0;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy