Package controllers

Source Code of controllers.RetrieveData

package controllers;

import java.net.URI;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.mail.Session;

import org.jaxen.function.FloorFunction;

import controllers.CompareUtils.BaseCompare;
import models.OAuthSession;
import models.PermissionSet;
import play.Logger;
import play.cache.Cache;
import play.libs.WS;
import play.libs.WS.HttpResponse;
import play.libs.WS.WSRequest;
import play.mvc.Controller;

import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

/*
* Reference: Play-ing in Java - By SANDEEP BHANOT
* http://blogs.developerforce.com/developer-relations/2011/08/play-ing-in-java.html
* https://github.com/sbhanot-sfdc/Play-Force
*/
public class RetrieveData extends Controller {
 
  private static final long MEM_THRESHOLD_MB = 10;
 
  /**
   * Use Force.com API to retrieve data (authentication with OAuth). Returns JsonObject.
   * @param query - SOQL query string
   * @return JsonObject with results
   */
  public static JsonObject query(String query, boolean retry) {
    OAuthSession oauth = ForceDotComOAuth2.getOAuthSession();
    if (oauth == null) {
      Application.index();
    }
    WSRequest req = WS.url(oauth.instance_url
        + "/services/data/v28.0/query/?q=%s", query);
    req.headers.put("Authorization", "OAuth " + oauth.access_token);
    HttpResponse response = req.get();

    int res = response.getStatus();
    if (res == 200) {
      return response.getJson().getAsJsonObject().getAsJsonObject();
    } else if (res == 400) {
      Logger.info("Response: 400 - Malformed query. Query: %s", query);
    } else if (res == 401) {
      Logger.info("Response: 401 - Calling refresh for query");
      retry = true;

      ForceDotComOAuth2.refreshToken(
          "https://login.salesforce.com/services/oauth2/token",
          System.getenv("clientKey"), System.getenv("clientSecret"));

      Logger.info("Refresh complete for query");
      query(query, retry);
     
    } else if (res == 500) {
      Logger.error("Response 500: Invalid query resulted in response code 500. Query was: %s", query);
    } else {
      Logger.error("Unexpected error. Response: %s", res);
    }
     
    return null;
  }
 
  /**
   * Retrieve results using Force.com API
   * @param itemType - User, PermissionSet, ProfilePermissionSet
   * @param queryLimit - max number of users to retrieve
   * @return JsonObject - results
   */
  public static JsonObject getItems(String itemType, String search, int queryLimit, boolean retry) {
    return  query(generateQuery(itemType, search, queryLimit), retry);
  }

  /**
   * Creates and returns SOQL query string
   * @param itemType - User, PermissionSet, ProfilePermissionSet
   * @param itemLimit - number of items to retrieve
   */
  private static String generateQuery(String itemType, String search, int itemLimit) {
    StringBuilder queryBuilder = new StringBuilder();
    queryBuilder.append("SELECT Id, ");
    boolean isProfilePermset = itemType.equals("ProfilePermissionSet");

    String displayField = "";
    if (itemType.equals("User")) {
      displayField = "Name";
      queryBuilder.append(displayField).append(" FROM User WHERE IsActive=true ");
    } else if (itemType.equals("PermissionSet")) {
      displayField = "Label";
      queryBuilder.append(displayField).append(" FROM PermissionSet WHERE IsOwnedByProfile=false ");
    } else if (isProfilePermset) {
      displayField = "Profile.Name";
      queryBuilder.append(displayField).append(" FROM PermissionSet WHERE IsOwnedByProfile=true ");
    }
   
    if (null != search && search.length() > 0) {
      String safeSearch = search.replace("'", "\\'");
      if (!safeSearch.startsWith("%") && !safeSearch.endsWith("%")) {
        // if search string doesn't specify 'starts with' or 'ends with', make generic match string
        safeSearch = "%" + safeSearch + "%";
      }
      queryBuilder.append("AND ").append(displayField).append(" LIKE '").append(safeSearch).append("' ");
    }
    queryBuilder.append("ORDER BY ").append(displayField);
    queryBuilder.append(" ASC NULLS LAST LIMIT ").append(itemLimit);

    Logger.info("QUERY: %s", queryBuilder.toString());
    return queryBuilder.toString();
  }
 

  /**
   * Calls the Describe method on PermissionSet via the Rest API to get the Permission Fields.
   * Uses caching and will use cached result, if possible.
   *
   * @param retry
   */
  public static JsonObject getUserPerms(boolean retry) {
    OAuthSession oauth = ForceDotComOAuth2.getOAuthSession();
    if (oauth == null) {
      Application.index();
    }
   
    String cacheKey = session.getId() + "-userperms";
    String userPerms = Cache.get(cacheKey, String.class);
    if (userPerms != null) {
      // cache hit
      Cache.replace(cacheKey, userPerms, "6mn")// keep cache warm
      return new JsonParser().parse(userPerms).getAsJsonObject();
    } else {
      // cache miss
      WSRequest req = WS.url(oauth.instance_url
          + "/services/data/v28.0/sobjects/%s/describe/", "PermissionSet");
      req.headers.put("Authorization", "OAuth " + oauth.access_token);
      HttpResponse response = req.get();
 
      int res = response.getStatus();
      if (res == 200) {
        JsonElement jsonResult = response.getJson();
        Cache.set(cacheKey, jsonResult.toString(), "6mn");
        return jsonResult.getAsJsonObject();
       
      } else if (res == 401) {
        Logger.info("Response: 400 - calling refresh in getUserPerms");
        retry = true;
 
        ForceDotComOAuth2.refreshToken(
            "https://login.salesforce.com/services/oauth2/token",
            System.getenv("clientKey"), System.getenv("clientSecret"));
 
        Logger.info("Refresh done for getUserPerms");
        getUserPerms(retry);
       
      } else {
        Logger.error("Error occured attempting to retrieve user perms. Response code: %s", res);
      }
    }
    return null// shouln't get get here, but need default return
  }
 
  /**
   * Build SOQL query string for all user permissions
   * @param permsetId
   * @param userPerms Set<String>
   */
  protected static String userPermQueryBuilder(String permsetId, Set<String> userPerms) {
    StringBuilder queryBuild = new StringBuilder();
    queryBuild.append("SELECT ");

    BaseCompare.appendParamsToQuery(queryBuild, BaseCompare.USER_PERMS, userPerms);
    queryBuild.append(" FROM PermissionSet WHERE Id=\'").append(permsetId).append("\'");

    return queryBuild.toString();
  }
 
  /**
   * Return JsonObject result of user perms for a specific permset.
   * Uses caching to prevent more queries than required.
   *
   * @param permsetId
   * @param userPerms Set<String>
   * @param retry
   */
  public static JsonObject getPermsetUserPerms(String permsetId, Set<String> userPerms, boolean retry) {
    String cacheKey = session.getId() + "-userperms-" + permsetId;
   
    String userPermCacheString = Cache.get(cacheKey, String.class);
    if (userPermCacheString != null) {
      // cache hit
      Cache.replace(cacheKey, userPermCacheString, "3mn")// keep cache warm
      return new JsonParser().parse(userPermCacheString).getAsJsonObject();
    } else {
      // cache miss
      JsonObject userPermJsonObject = query(userPermQueryBuilder(permsetId, userPerms), retry);
      if (!freeMemoryBelowThreshold()) {
        Cache.set(cacheKey, userPermJsonObject.toString(), "3mn");
      }
      return userPermJsonObject;
    }
  }
 
  /**
   * Get the SetupEntityAccess Ids for a particular permset.
   * Uses caching.
   *
   * @param permsetId
   * @param retry
   * @return
   */
  public static List<JsonObject> getSetupAccessIds(String permsetId, boolean retry) {
    List<JsonObject> results = Lists.newArrayList();
    JsonArray resultsArray = new JsonArray();
   
    String cacheKey = session.getId() + "-setupaccess-" + permsetId;
    String setupAccessString = Cache.get(cacheKey, String.class);
    if (setupAccessString != null) {
      // cache hit
      Cache.replace(cacheKey, setupAccessString, "3mn")// keep cache warm
      resultsArray = new JsonParser().parse(setupAccessString).getAsJsonArray();
    } else {
      // cache miss
      String seaQuery = buildSeaPermQuery(permsetId);
      resultsArray = RetrieveData.query(seaQuery, retry).get("records").getAsJsonArray();     
      if (!freeMemoryBelowThreshold()) {
        Cache.set(cacheKey, resultsArray.toString(), "3mn");
      }
    }
    removeCacheElementIfMemoryLow(cacheKey);
   
    for (JsonElement jsElement : resultsArray) {
      results.add(jsElement.getAsJsonObject());
    }
    return results;
  }
 
  /**
   * Returns SetupEntityAccess perm SOQL query string
   * @param parentId - UserId or PermissionSet / ProfileId
   */
  private static String buildSeaPermQuery(String parentId) {
    StringBuilder query = new StringBuilder("SELECT SetupEntityId FROM SetupEntityAccess WHERE ParentId");
    if (parentId.startsWith(BaseCompare.PERMSET_ID_PREFIX)) {
      query.append("='").append(parentId).append("'");
    } else {
      query.append(" IN (SELECT PermissionSetId from PermissionSetAssignment WHERE ");
      if (parentId.startsWith(BaseCompare.USER_ID_PREFIX)) {
        query.append("AssigneeId='");
      } else if (parentId.startsWith(BaseCompare.PROFILE_ID_PREFIX)) {
        query.append("ProfileId='");
      } else {
        Logger.warn("Invalid parentId prefix.  ParentId: %s", parentId);
      }
      // TODO throw exception - don't allow invalid query string
      query.append(parentId).append("')");
    }
    return query.toString();
  }
 
  /**
   * Retrieve SetupEntity names / labels.
   * Uses caching if possible.
   *
   * @param isAppType - Tabset or Connected App
   * @param apiName
   * @param idList
   * @param retry
   * @return JsonArray results
   */
  public static List<JsonObject> getSetupEntityNames(boolean isAppType,
      String apiName, ArrayList<String> idList, boolean retry) {
    List<JsonObject> results = Lists.newArrayList();
    List<String> uncachedIds = Lists.newArrayList();
   
    Logger.info("[%s] Number of Ids in idList: %d", apiName, idList.size());

    String cacheKeyPrefix = session.getId() + "-setupentity-";
    // find all cached SEA names and add to results list and determine uncached ids
    for (String id : idList) {
      String cacheKey = cacheKeyPrefix + id;

      String setupEntityNameJson = Cache.get(cacheKey, String.class);
      if (setupEntityNameJson != null) {
        // cache hit - add result to results list
        results.add(new JsonParser().parse(setupEntityNameJson).getAsJsonObject());
        Cache.replace(cacheKey, setupEntityNameJson, "3mn")// keep cache warm
      } else {
        // cache miss on setup entity name
        uncachedIds.add(id);
      }
    }

    // query to get names for uncached ids
    if (!uncachedIds.isEmpty()) {
      Logger.info("[%s] Number of uncached Ids: %d", apiName, uncachedIds.size());

      // to avoid getting 413 (soql request too large), batch name queries in groups of 200
      int BATCH_SIZE = 200;
      int numNamesToRetrieve = uncachedIds.size();

      while(numNamesToRetrieve > 0) {
        List<String> namesToRetrieve = Lists.newArrayList();
        if (numNamesToRetrieve < BATCH_SIZE) {
          namesToRetrieve.addAll(uncachedIds);
          uncachedIds.clear();
        } else {
          // get batch of names to retrieve
          namesToRetrieve.addAll(uncachedIds.subList(0, BATCH_SIZE));
          uncachedIds.subList(0, BATCH_SIZE).clear();
         
        }
        numNamesToRetrieve = uncachedIds.size();
        String labelQuery = String.format(
            "SELECT Id, %s FROM %s WHERE Id IN (%s)", isAppType ? "Label"
                : "Name", apiName, buildIdListString(namesToRetrieve));
       
        JsonArray uncachedResults = RetrieveData.query(labelQuery, retry)
            .get("records").getAsJsonArray();
       
        // for each entity returned, cache result and add to results list
        for (JsonElement jsonElement : uncachedResults) {
          JsonObject jsonObj = jsonElement.getAsJsonObject();
          if (!freeMemoryBelowThreshold()) {
            Cache.set(cacheKeyPrefix + jsonObj.get("Id").getAsString(), jsonObj.toString(), "3mn");
          }
          results.add(jsonObj);
        }
      }
    }
   
    // results is combination of cached and uncached SetupEntityName JsonObjects
    return results;
  }
 
  /**
   * Take List<String> and join with single quotes for use in SOQL query
   *
   * @param idList
   * @return idList String
   */
  private static String buildIdListString(List<String> idList) {
    StringBuilder builder = new StringBuilder();
    if (idList.isEmpty()) {
      return "\'\'";
    }
    Iterator itter = idList.iterator();
    while (itter.hasNext()) {
      builder.append("\'" + itter.next() + "\'");
      if (itter.hasNext()) { builder.append(","); }
    }
    return builder.toString();
  }
 
  private static void removeCacheElementIfMemoryLow(String cacheKey) {
        if (freeMemoryBelowThreshold()) {
          Logger.error("Free Memory below threshold. Clearning cache element: %s.", cacheKey);
          Cache.delete(cacheKey);
        }
  }
 
  /**
   * Check runtime.freeMemory and check if free memory is less than specified threshold.
   * @return boolean freeMemoryLessThanThreshold
   */
  private static boolean freeMemoryBelowThreshold() {
        final long freeMemory = Runtime.getRuntime().freeMemory() / (1024*1024);
        boolean freeMemoryLessThanThreshold = freeMemory < MEM_THRESHOLD_MB;
        if (freeMemoryLessThanThreshold) {
          Logger.warn("Free Memory less than specified threshold.");
        }
    return freeMemoryLessThanThreshold;
  }
 
}
TOP

Related Classes of controllers.RetrieveData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.