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

com.mediamath.terminalone.service.ReportService Maven / Gradle / Ivy

There is a newer version: 1.2.2
Show newest version
/*******************************************************************************
 * Copyright 2016 MediaMath
 * 
 * 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.
 ******************************************************************************/

package com.mediamath.terminalone.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map.Entry;

import javax.ws.rs.core.Response;

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

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.reflect.TypeToken;
import com.mediamath.terminalone.Connection;
import com.mediamath.terminalone.ReportCriteria;
import com.mediamath.terminalone.exceptions.ClientException;
import com.mediamath.terminalone.models.JsonResponse;
import com.mediamath.terminalone.models.T1Entity;
import com.mediamath.terminalone.models.T1User;
import com.mediamath.terminalone.models.reporting.Having;
import com.mediamath.terminalone.models.reporting.ReportError;
import com.mediamath.terminalone.models.reporting.ReportErrorEntityInfo;
import com.mediamath.terminalone.models.reporting.ReportFilter;
import com.mediamath.terminalone.models.reporting.ReportStatus;
import com.mediamath.terminalone.models.reporting.ReportValidationResponse;
import com.mediamath.terminalone.models.reporting.Reports;
import com.mediamath.terminalone.models.reporting.meta.Meta;
import com.mediamath.terminalone.models.reporting.meta.MetaData;
import com.mediamath.terminalone.models.reporting.meta.MetaDimensionData;
import com.mediamath.terminalone.models.reporting.meta.MetaDimensions;
import com.mediamath.terminalone.models.reporting.meta.MetaMetrics;
import com.mediamath.terminalone.models.reporting.meta.MetricsData;
import com.mediamath.terminalone.models.reporting.meta.TimeField;
import com.mediamath.terminalone.models.reporting.meta.TimeInterval;
import com.mediamath.terminalone.utils.Utility;

public class ReportService {

  private static final String UTF_8 = "UTF-8";

  private static final Logger logger = LoggerFactory.getLogger(ReportService.class);

  private static final String META = "meta";

  private static final String YYYY_MM_DD_T_HH_MM_SS = "yyyy-MM-dd'T'HH:mm:ss";

  /**
   * gets uri for report meta data.
   * 
   * @return StringBuilder object.
   * 
   */
  public StringBuilder getMetaUri() {
    StringBuilder path = new StringBuilder();
    path.append(META);
    return path;
  }

  /**
   * gets uri for reports.
   * 
   * @param report
   *          expects a ReportCriteria entity.
   * 
   * @return StringBuilder object.
   */
  public StringBuilder getReportUri(ReportCriteria report) {
    StringBuilder path;

    if (report == null)
      return null;

    path = new StringBuilder(report.getReportName());

    try {
      // dimensions
      filterDimensions(report, path);

      // filters
      addFilters(report, path);

      // having.
      addHaving(report, path);

      // metrics
      filterMetrics(report, path);

      // time rollup.
      filterTimeRollUp(report, path);

      // time_ window or start_date or end_date
      filterTimeWindowStartDateEndDate(report, path);

      // order
      filterOrder(report, path);

      // pagelimit & page offset
      filterPageLimitPageOffset(report, path);

      // precision
      if (report.getPrecision() > 0) {
        path.append("&precision=" + report.getPrecision());
      }

    } catch (UnsupportedEncodingException exception) {
      logger.debug("getReportUri: UnsupportedEncodingException occured: ");
      Utility.logStackTrace(exception);
    }

    return path;
  }

  private void filterPageLimitPageOffset(ReportCriteria report, StringBuilder path) {
    if (report.getPageLimit() != null && !report.getPageLimit().isEmpty()
        && (report.getPageOffset() == null || report.getPageOffset().isEmpty())) {

      uriAppender(path);
      path.append("page_limit=" + report.getPageLimit());

    } else if (report.getPageOffset() != null && !report.getPageOffset().isEmpty()
        && report.getPageLimit() != null && !report.getPageLimit().isEmpty()) {

      uriAppender(path);
      path.append("page_limit=" + report.getPageLimit());
      path.append("&page_offset=" + report.getPageOffset());
    }
  }

  private void filterOrder(ReportCriteria report, StringBuilder path) {
    if (report.getOrder() != null && !report.getOrder().isEmpty()) {

      uriAppender(path);

      StringBuilder buffer = new StringBuilder();
      for (String order : report.getOrder()) {
        if (buffer.length() == 0) {
          buffer.append("order=" + order);
        } else {
          buffer.append("," + order);
        }
      }
      path.append(buffer);
    }
  }

  private void filterTimeWindowStartDateEndDate(ReportCriteria report, StringBuilder path) {
    if (report.getTimeWindow() != null && !report.getTimeWindow().isEmpty()
        && report.getStartDate() == null && report.getEndDate() == null) {

      uriAppender(path);

      path.append("time_window=" + report.getTimeWindow());

    } else if (checkTimeWindow(report) && checkStartDate(report) && checkEndDate(report)) {

      uriAppender(path);

      path.append("start_date=" + report.getStartDate());
      path.append("&end_date=" + report.getEndDate());

    }
  }
  
  private boolean checkEndDate(ReportCriteria report) {
    return report.getEndDate() != null && !report.getEndDate().isEmpty();
  }
  
  private boolean checkStartDate(ReportCriteria report) {
    return report.getStartDate() != null && !report.getStartDate().isEmpty();
  }

  private boolean checkTimeWindow(ReportCriteria report) {
    return report.getTimeWindow() == null;
  }

  private void filterTimeRollUp(ReportCriteria report, StringBuilder path) {
    if (report.getTimeRollup() != null && !report.getTimeRollup().isEmpty()) {
      uriAppender(path);

      path.append("time_rollup=" + report.getTimeRollup());
    }
  }

  private void filterMetrics(ReportCriteria report, StringBuilder path)
      throws UnsupportedEncodingException {
    if (report.getMetrics() != null && !report.getMetrics().isEmpty()) {

      if (path.indexOf("?") == -1) {
        path.append("?metrics=");
      } else {
        path.append("&metrics=");
      }

      StringBuilder buffer = new StringBuilder();
      for (String metric : report.getMetrics()) {
        if (buffer.length() == 0) {
          buffer.append(metric);
        } else {
          buffer.append("," + metric);
        }
      }
      path.append(URLEncoder.encode(buffer.toString(), UTF_8));
    }
  }

  private void addHaving(ReportCriteria report, StringBuilder path)
      throws UnsupportedEncodingException {
       
    if (report.getHaving() != null && !report.getHaving().isEmpty()) {

      if (path.indexOf("?") == -1) {
        path.append("?having=");
      } else {
        path.append("&having=");
      }

      StringBuilder buffer = buildHavingCriteria(report);
      // encode
      path.append(URLEncoder.encode(buffer.toString(), UTF_8));
    }
  }

  private StringBuilder buildHavingCriteria(ReportCriteria report) {
    StringBuilder buffer = new StringBuilder();
    int havingSize = 0;
    for (Having having : report.getHaving()) {
      if (checkHavingKey(having) && checkHavingOperator(having) && checkHavingValue(having)) {

        buffer.append(having.getKey() + having.getOperator() + having.getValue());

        if (havingSize != report.getHaving().size() - 1) {
          buffer.append("&");
        }
        havingSize++;
      }
    }
    return buffer;
  }
  
  private boolean checkHavingValue(Having having) {
    return having.getValue() != null && !having.getValue().isEmpty();
  }
  
  private boolean checkHavingKey(Having having) {
    return having.getKey() != null && !having.getKey().isEmpty();
  }
  
  private boolean checkHavingOperator(Having having) {
    return having.getOperator() != null && !having.getOperator().isEmpty();
  }

  private void addFilters(ReportCriteria report, StringBuilder path)
      throws UnsupportedEncodingException {
    if (report.getFilters() != null && !report.getFilters().isEmpty()) {

      if (path.indexOf("?") == -1) {
        path.append("?filter=");
      } else {
        path.append("&filter=");
      }

      StringBuilder buffer = buildFilterCriteria(report);
      // encode
      path.append(URLEncoder.encode(buffer.toString(), UTF_8));
    }
  }

  private StringBuilder buildFilterCriteria(ReportCriteria report) {
    int filterSize = 0;
    StringBuilder buffer = new StringBuilder();
    for (ReportFilter f : report.getFilters()) {
      if (checkFilterKey(f) && checkFilterOperator(f) && checkFilterValue(f)) {
        buffer.append(f.getKey() + f.getOperator() + f.getValue());
        if (filterSize != report.getFilters().size() - 1) {
          buffer.append("&");
        }
        filterSize++;
      }
    }
    return buffer;
  }
  
  private boolean checkFilterKey(ReportFilter f) {
    return f.getKey() != null && !f.getKey().isEmpty();
  }
  
  private boolean checkFilterOperator(ReportFilter f) {
    return f.getOperator() != null && !f.getOperator().isEmpty();
  }
  
  private boolean checkFilterValue(ReportFilter f) {
    return f.getValue() != null && !f.getValue().isEmpty();
  }

  private void filterDimensions(ReportCriteria report, StringBuilder path)
      throws UnsupportedEncodingException {
    if (report.getDimensions() != null && !report.getDimensions().isEmpty()) {

      if (path.indexOf("?") == -1) {
        path.append("?dimensions=");
      } else {
        path.append("&dimensions=");
      }

      StringBuilder buffer = new StringBuilder();
      for (String dimension : report.getDimensions()) {
        if (buffer.length() == 0) {
          buffer.append(dimension);
        } else {
          buffer.append("," + dimension);
        }
      }
      // Encode
      path.append(URLEncoder.encode(buffer.toString(), UTF_8));
    }
  }

  private void uriAppender(StringBuilder path) {
    if (path.indexOf("?") == -1) {
      path.append("?");
    } else {
      path.append("&");
    }
  }

  /**
   * this method parses meta query response.
   * 
   * @param response
   *          requires the JSON response.
   * @return JsonResponse returns JsonResponse of type T.
   * 
   */
  public JsonResponse parseMetaResponse(String response) {
    JsonParser parser = new JsonParser();
    JsonResponse finalResponse;
    JsonObject obj = parser.parse(response).getAsJsonObject();

    JsonElement reportsElement = obj.get("reports");
    JsonObject reportsObj = reportsElement.getAsJsonObject();

    if (reportsObj == null)
      return null;

    Meta meta = new Meta();
    Type type = new TypeToken() {
    }.getType();

    HashMap metaData = new HashMap<>();

    GsonBuilder builder = new GsonBuilder();
    builder.setDateFormat(YYYY_MM_DD_T_HH_MM_SS);
    Gson gson = builder.create();

    for (Entry a : reportsObj.entrySet()) {
      String key = a.getKey();
      MetaData value = gson.fromJson(a.getValue(), type);
      metaData.put(key, value);
    }
    meta.setMetaData(metaData);
    finalResponse = new JsonResponse<>(meta);

    return finalResponse;
  }

  /**
   * parses the meta data response for a particular report query.
   * 
   * @param response
   *          requires JSON response.
   * @return MetaData object.
   */
  public MetaData parseReportMetaResponse(String response) {

    GsonBuilder builder = new GsonBuilder();
    builder.setDateFormat(YYYY_MM_DD_T_HH_MM_SS);
    Gson gson = builder.create();
    MetaData data = gson.fromJson(response, MetaData.class);

    JsonParser parser = new JsonParser();
    JsonObject obj = parser.parse(response).getAsJsonObject();
    JsonElement reportsElement = obj.get("structure");

    JsonObject dimensionObj = reportsElement.getAsJsonObject().get("dimensions").getAsJsonObject();
    JsonObject metricsObj = reportsElement.getAsJsonObject().get("metrics").getAsJsonObject();
    JsonObject timefieldObj = reportsElement.getAsJsonObject().get("time_field").getAsJsonObject();

    // dimensions
    parseDimensions(gson, data, dimensionObj);

    // metrics
    parseMetrics(gson, data, metricsObj);

    // time_field
    parseTimeField(gson, data, timefieldObj);

    return data;
    // end
  }

  private void parseTimeField(Gson gson, MetaData data, JsonObject timefieldObj) {
    if (timefieldObj != null) {

      TimeField timefield = new TimeField();
      HashMap timeFieldMap = new HashMap<>();

      for (Entry a : timefieldObj.entrySet()) {
        String key = a.getKey();
        TimeInterval value = gson.fromJson(a.getValue(), TimeInterval.class);
        timeFieldMap.put(key, value);
      }

      timefield.setData(timeFieldMap);
      data.getStructure().setTimeField(timefield);
    }
  }

  private void parseMetrics(Gson gson, MetaData data, JsonObject metricsObj) {
    if (metricsObj != null) {
      MetaMetrics metrics = new MetaMetrics();
      HashMap metricsMap = new HashMap<>();

      for (Entry a : metricsObj.entrySet()) {
        String key = a.getKey();
        MetricsData value = gson.fromJson(a.getValue(), MetricsData.class);
        metricsMap.put(key, value);
      }

      metrics.setMetricsMap(metricsMap);
      data.getStructure().setMetrics(metrics);
    }
  }

  private void parseDimensions(Gson gson, MetaData data, JsonObject dimensionObj) {
    if (dimensionObj != null) {
      MetaDimensions dimensions = new MetaDimensions();
      HashMap dimensionsInfoMap = new HashMap<>();

      for (Entry a : dimensionObj.entrySet()) {
        String key = a.getKey();
        MetaDimensionData value = gson.fromJson(a.getValue(), MetaDimensionData.class);
        dimensionsInfoMap.put(key, value);
      }

      dimensions.setDimensionsInfoMap(dimensionsInfoMap);
      data.getStructure().setDimensions(dimensions);
    }
  }

  /**
   * Gets Report Data.
   * 
   * @param report
   *          type of report for which you want to query.
   * @param finalPath
   *          path to hit the API endpoint.
   * @param connection
   *          requires a Connection endpoint.
   * @param user
   *          requires a valid user login session.
   * @throws ClientException
   *           a client exception is thrown if any error occurs.
   */
  public BufferedReader getReportData(Reports report, String finalPath, Connection connection,
      T1User user) throws ClientException {

    Response response = connection.getReportData(finalPath, user);
    BufferedReader reader = null;
    if ("text".equalsIgnoreCase(response.getMediaType().getType()) && "xml".equalsIgnoreCase(response.getMediaType().getSubtype()) && response.getStatus() != 200) {
      try {

        ObjectMapper xmlMapper = new XmlMapper();
        String error = response.readEntity(String.class);
        ReportError re = xmlMapper.readValue(error, ReportError.class);
        throwReportError(re);

      } catch (JsonParseException jsonParseException) {
        Utility.logStackTrace(jsonParseException);
        throw new ClientException("Json Parse Exception Occured");
      } catch (JsonMappingException jsonMappingException) {
        Utility.logStackTrace(jsonMappingException);
        throw new ClientException("Json Mapping Exception Occured");
      } catch (IOException ioException) {
        Utility.logStackTrace(ioException);
        throw new ClientException("IO Exception Occured");
      }

    } else if ("text".equalsIgnoreCase(response.getMediaType().getType()) 
          && "csv".equalsIgnoreCase(response.getMediaType().getSubtype())
          && response.getStatus() == 200) {
      
      InputStream responseStream = response.readEntity(InputStream.class);
      reader = new BufferedReader(new InputStreamReader(responseStream));
    }
    return reader;
  }

  /**
   * validates the Report Data.
   * 
   * @param report
   *          the specific report you want to validate.
   * 
   * @param finalPath
   *          path to API endpoint.
   * @param connection
   *          requires a connection object.
   * @param user
   *          requires a valid user login session.
   * @return ReportValidationResponse object.
   * @throws ClientException
   *           a client exception is thrown if any error occurs.
   */
  public ReportValidationResponse validateReportData(Reports report, String finalPath,
      Connection connection, T1User user) throws ClientException {

    Response response = connection.getReportData(finalPath, user);
    ReportValidationResponse re = null;

    if ("text".equalsIgnoreCase(response.getMediaType().getType()) && "xml".equalsIgnoreCase(response.getMediaType().getSubtype())) {

      try {

        ObjectMapper xmlMapper = new XmlMapper();
        String error = response.readEntity(String.class);
        re = xmlMapper.readValue(error, ReportValidationResponse.class);

      } catch (JsonParseException jsonParseException) {
        Utility.logStackTrace(jsonParseException);
        throw new ClientException("Json Parse Exception Occured");
      } catch (JsonMappingException jsonMappingException) {
        Utility.logStackTrace(jsonMappingException);
        throw new ClientException("Json Mapping Exception Occured");
      } catch (IOException ioException) {
        Utility.logStackTrace(ioException);
        throw new ClientException("IO Exception Occured");
      }

    }
    return re;
  }

  private void throwReportError(ReportError re) throws ClientException {
    if (re != null) {

      StringBuilder buffer = new StringBuilder();

      parseErrorEntity(re, buffer);

      parseErrorStatus(re, buffer);

      throw new ClientException(buffer.toString());
    }

  }

  private void parseErrorStatus(ReportError re, StringBuilder buffer) {
    if (re.getStatus() != null && re.getStatus().length > 0) {
      for (ReportStatus stats : re.getStatus()) {
        if (checkStatusCode(stats) && checkStatusReason(stats) && checkStatusValue(stats)) {
          buffer.append("Status[ Code: " + stats.getCode() + ", Reason: " + stats.getReason()
              + ", value: " + stats.getValue() + " ]");
        }
      }
    }
  }
  
  private boolean checkStatusValue(ReportStatus stats) {
    return stats.getValue() != null && !stats.getValue().isEmpty();
  }
  
  private boolean checkStatusReason(ReportStatus stats) {
    return stats.getReason() != null && !stats.getReason().isEmpty();
  }

  private boolean checkStatusCode(ReportStatus stats) {
    return stats.getCode() != null && !stats.getCode().isEmpty();
  }

  private void parseErrorEntity(ReportError re, StringBuilder buffer) {
    if (re.getEntity() != null && re.getEntity().length > 0) {
      for (ReportErrorEntityInfo rentity : re.getEntity()) {

        if (rentity.getId() != null && rentity.getType() != null && !rentity.getId().isEmpty()
            && !rentity.getType().isEmpty()) {
          buffer.append("Entity[ ID: " + rentity.getId() + ", Type: " + rentity.getType() + " ]");
        }
      }

    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy