com.auditbucket.client.AbRestClient.java Source code

Java tutorial

Introduction

Here is the source code for com.auditbucket.client.AbRestClient.java

Source

/*
 * Copyright (c) 2012-2014 "Monowai Developments Limited"
 *
 * This file is part of AuditBucket.
 *
 * AuditBucket 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.
 *
 * AuditBucket 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 AuditBucket.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.auditbucket.client;

import com.auditbucket.registration.bean.FortressInputBean;
import com.auditbucket.registration.bean.FortressResultBean;
import com.auditbucket.registration.bean.TagInputBean;
import com.auditbucket.track.bean.CrossReferenceInputBean;
import com.auditbucket.track.bean.MetaInputBean;
import com.auditbucket.track.bean.TrackResultBean;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Template to support writing Audit and Tag information to a remote AuditBucket instance.
 *
 * @see Importer
 *      <p/>
 *      User: Mike Holdsworth
 *      Since: 13/10/13
 */
public class AbRestClient {

    private String NEW_HEADER;
    private String NEW_TAG;
    private String CROSS_REFERENCES;
    private String FORTRESS;
    private String PING;
    private final String userName;
    private final String password;
    private int batchSize;
    private static boolean compress = true;
    private boolean simulateOnly;
    private List<MetaInputBean> batchHeader = new ArrayList<>();
    private Map<String, TagInputBean> batchTag = new HashMap<>();
    private final String headerSync = "BatchSync";
    private final String tagSync = "TagSync";
    private String defaultFortress;

    public String ping() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
        HttpHeaders httpHeaders = getHeaders(userName, password);
        HttpEntity requestEntity = new HttpEntity<>(httpHeaders);
        try {
            ResponseEntity<String> response = restTemplate.exchange(PING, HttpMethod.GET, requestEntity,
                    String.class);
            return response.getBody();
        } catch (HttpClientErrorException e) {
            // ToDo: Rest error handling pretty useless. need to know why it's failing
            logger.error("AB Client Audit error {}", getErrorMessage(e));
            return "err";
        } catch (HttpServerErrorException e) {
            logger.error("AB Server Audit error {}", getErrorMessage(e));
            return "err";

        }

    }

    public enum type {
        AUDIT, TAG
    }

    private static org.slf4j.Logger logger = LoggerFactory.getLogger(AbRestClient.class);

    public AbRestClient(String serverName, String userName, String password, int batchSize) {
        this(serverName, userName, password, batchSize, null);
    }

    public AbRestClient(String serverName, String userName, String password, int batchSize,
            String defaultFortress) {
        this.userName = userName;
        this.password = password;
        // Urls to write Audit/Tag/Fortress information
        this.NEW_HEADER = serverName + "/v1/track/";
        this.PING = serverName + "/v1/admin/ping";
        this.CROSS_REFERENCES = serverName + "/v1/track/xref";
        this.NEW_TAG = serverName + "/v1/tag/";
        this.FORTRESS = serverName + "/v1/fortress/";
        this.batchSize = batchSize;
        this.defaultFortress = defaultFortress;
    }

    public void setSimulateOnly(boolean simulateOnly) {
        this.simulateOnly = simulateOnly;
    }

    public int flushXReferences(List<CrossReferenceInputBean> referenceInputBeans) {
        logger.info("Processing [{}] cross references - simulate [{}]", referenceInputBeans.size(), simulateOnly);
        if (simulateOnly)
            return 0;
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
        HttpHeaders httpHeaders = getHeaders(userName, password);
        HttpEntity<List<CrossReferenceInputBean>> requestEntity = new HttpEntity<>(referenceInputBeans,
                httpHeaders);
        try {
            ResponseEntity<ArrayList> response = restTemplate.exchange(CROSS_REFERENCES, HttpMethod.POST,
                    requestEntity, ArrayList.class);
            logServerMessages(response);
            return referenceInputBeans.size();
        } catch (HttpClientErrorException e) {
            // ToDo: Rest error handling pretty useless. need to know why it's failing
            logger.error("AB Client Audit error {}", getErrorMessage(e));
            return 0;
        } catch (HttpServerErrorException e) {
            logger.error("AB Server Audit error {}", getErrorMessage(e));
            return 0;

        }

    }

    private String flushAudit(List<MetaInputBean> auditInput) {
        if (simulateOnly || auditInput.isEmpty())
            return "OK";
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter());

        HttpHeaders httpHeaders = getHeaders(userName, password);
        HttpEntity<List<MetaInputBean>> requestEntity = new HttpEntity<>(auditInput, httpHeaders);

        try {
            restTemplate.exchange(NEW_HEADER, HttpMethod.PUT, requestEntity, TrackResultBean.class);
            return "OK";
        } catch (HttpClientErrorException e) {
            // ToDo: Rest error handling pretty useless. need to know why it's failing
            logger.error("AB Client Audit error {}", getErrorMessage(e));
            return null;
        } catch (HttpServerErrorException e) {
            logger.error("AB Server Audit error {}", getErrorMessage(e));
            return null;

        }
    }

    public String flushTags(List<TagInputBean> tagInputBean) {
        if (tagInputBean.isEmpty())
            return "OK";
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter());

        HttpHeaders httpHeaders = getHeaders(userName, password);
        HttpEntity<List<TagInputBean>> requestEntity = new HttpEntity<>(tagInputBean, httpHeaders);

        try {
            // ToDo logServerMessage - error state will be returned in arraylist
            ResponseEntity<ArrayList> response = restTemplate.exchange(NEW_TAG, HttpMethod.PUT, requestEntity,
                    ArrayList.class);
            logServerMessages(response);
            return "OK";
        } catch (HttpClientErrorException e) {
            // to test, try to log against no existing fortress.
            logger.error("Datagio server error processing Tags {}", getErrorMessage(e));
            return null;
        } catch (HttpServerErrorException e) {
            logger.error("Datagio server error processing Tags {}", getErrorMessage(e));
            return null;

        }
    }

    private void logServerMessages(ResponseEntity<ArrayList> response) {
        ArrayList x = response.getBody();
        for (Object val : x) {
            Map map = (Map) val;
            Object serviceMessage = map.get("serviceMessage");
            if (serviceMessage != null)
                logger.error("Service returned [{}]", serviceMessage.toString());
        }
    }

    public void ensureFortress(String fortressName) {
        if (fortressName == null)
            return;

        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter());

        HttpHeaders httpHeaders = getHeaders(userName, password);
        HttpEntity<FortressInputBean> request = new HttpEntity<>(new FortressInputBean(fortressName, false),
                httpHeaders);
        try {
            restTemplate.exchange(FORTRESS, HttpMethod.POST, request, FortressResultBean.class);
            if (defaultFortress != null && !defaultFortress.equals(fortressName)) {
                request = new HttpEntity<>(new FortressInputBean(defaultFortress, false), httpHeaders);
                restTemplate.exchange(FORTRESS, HttpMethod.POST, request, FortressResultBean.class);
            }
        } catch (HttpClientErrorException e) {
            // ToDo: Rest error handling pretty useless. need to know why it's failing
            logger.error("AB Client Audit error {}", getErrorMessage(e));
        } catch (HttpServerErrorException e) {
            logger.error("AB Server Audit error {}", getErrorMessage(e));

        }
    }

    public String getErrorMessage(HttpStatusCodeException e) {

        if (e.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR) {
            logger.error(e.getResponseBodyAsString());
            return e.getResponseBodyAsString();
        }

        JsonNode n = null;
        try {
            n = mapper.readTree(e.getResponseBodyAsByteArray());
        } catch (IOException e1) {

            logger.error(String.valueOf(e1));
        }
        String message;
        if (n != null)
            message = String.valueOf(n.get("message"));
        else
            message = e.getMessage();

        return message;
    }

    private static HttpHeaders headers = null;

    public static HttpHeaders getHeaders(final String username, final String password) {
        if (headers != null)
            return headers;

        headers = new HttpHeaders() {
            {
                String auth = username + ":" + password;
                byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII")));
                String authHeader = "Basic " + new String(encodedAuth);
                set("Authorization", authHeader);
                setContentType(MediaType.APPLICATION_JSON);
                set("charset", "UTF-8");
                if (compress)
                    set("Accept-Encoding", "gzip,deflate");
            }
        };

        return headers;
    }

    public void flush(String message) {
        flush(message, type.TAG);
        flush(message, type.AUDIT);
    }

    /**
     * push any remaining updates
     */
    public void flush(String message, type abType) {
        if (simulateOnly)
            return;
        if (abType.equals(type.AUDIT)) {
            synchronized (headerSync) {
                writeAudit(null, true, message);
            }
        } else {
            synchronized (tagSync) {
                writeTag(null, true, message);
            }
        }
    }

    /**
     * send the data to AuditBucket
     *
     * @param metaInputBean Input to push
     */
    public void writeAudit(MetaInputBean metaInputBean, String message) {
        writeAudit(metaInputBean, false, message);
    }

    private void batchTags(MetaInputBean metaInputBeans) {

        for (TagInputBean tag : metaInputBeans.getTags()) {
            String indexKey = tag.getCode() + tag.getIndex();
            TagInputBean cachedTag = batchTag.get(indexKey);
            if (cachedTag == null)
                batchTag.put(indexKey, tag);
            else {
                cachedTag.mergeTags(tag);
            }
        }
    }

    void writeAudit(MetaInputBean metaInputBean, boolean flush, String message) {

        synchronized (headerSync) {
            if (metaInputBean != null) {
                if (metaInputBean.getFortress() == null)
                    metaInputBean.setFortress(defaultFortress);
                batchHeader.add(metaInputBean);
                batchTags(metaInputBean);
            }

            if (flush || batchHeader.size() == batchSize) {

                if (batchHeader.size() >= 1) {
                    logger.debug("Flushing....");
                    // process the tags independently to reduce the chance of a deadlock when processing the header
                    flushTags(new ArrayList<>(batchTag.values()));
                    flushAudit(batchHeader);
                    logger.debug("Flushed " + message + " Batch [{}]", batchHeader.size());
                }
                batchHeader = new ArrayList<>();
                batchTag = new HashMap<>();
            }

        }

    }

    public void writeTag(TagInputBean tagInputBean, String message) {
        writeTag(tagInputBean, false, message);
    }

    private void writeTag(TagInputBean tagInputBean, boolean flush, String message) {

        synchronized (tagSync) {
            if (tagInputBean != null)
                batchTag.put(tagInputBean.getName() + tagInputBean.getIndex(), tagInputBean);

            if (flush || batchTag.size() == batchSize) {
                logger.debug("Flushing " + message + " Tag Batch [{}]", batchTag.size());
                if (batchTag.size() >= 0)
                    flushTags(new ArrayList<>(batchTag.values()));
                logger.debug("Tag Batch Flushed");
                batchTag = new HashMap<>();
            }
        }

    }

    static final ObjectMapper mapper = new ObjectMapper();

    public static Map<String, Object> getWeightedMap(int weight) {
        Map<String, Object> properties = new HashMap<>();
        properties.put("weight", weight);
        return properties;
    }

    /**
     * Converts the strings to a simple JSON representation
     *
     * @param headerRow - keys
     * @param line      - values
     * @return JSON Object
     * @throws JsonProcessingException
     */
    public static String convertToJson(String[] headerRow, String[] line) throws JsonProcessingException {
        ObjectNode node = mapper.createObjectNode();
        for (int i = 0; i < headerRow.length; i++) {
            node.put(headerRow[i], line[i].trim());
        }
        return node.toString();
    }

}