/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package controllers.util; import com.emc.storageos.model.DataObjectRestRep; import com.emc.storageos.model.NamedRelatedResourceRep; import com.emc.storageos.model.RelatedResourceRep; import com.emc.vipr.client.core.util.ResourceUtils; import static com.emc.vipr.client.core.util.ResourceUtils.name; import static com.emc.vipr.client.core.util.ResourceUtils.uris; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import controllers.Common; import java.net.URI; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import play.Logger; import play.libs.F.Promise; import play.mvc.Controller; import play.mvc.Http; import play.mvc.Router; import play.mvc.With; import util.MessagesUtils; import util.StringOption; import util.datatable.DataTablesSupport; @With(Common.class) public class ViprResourceController extends Controller { protected static final String DISCOVERY_STARTED = "PhysicalAssets.introspection"; protected static final String DEREGISTER_SUCCESS = "PhysicalAssets.deregistration.success"; protected static final String DEREGISTER_ERROR = "PhysicalAssets.deregistration.error"; protected static final String REGISTER_SUCCESS = "PhysicalAssets.registration.success"; protected static final String REGISTER_ERROR = "PhysicalAssets.registration.error"; protected static boolean isTrue(Boolean value) { return Boolean.TRUE.equals(value); } protected static boolean isFalse(Boolean value) { return Boolean.FALSE.equals(value); } protected static boolean isNotTrue(Boolean value) { return !Boolean.TRUE.equals(value); } protected static boolean isNotFalse(Boolean value) { return !Boolean.FALSE.equals(value); } protected static <T> T defaultValue(T value, T defaultValue) { return value != null ? value : defaultValue; } protected static int defaultInt(Integer value) { return defaultInt(value, 0); } protected static int defaultInt(Integer value, int defaultValue) { return value != null ? value : defaultValue; } protected static boolean defaultBoolean(Boolean value) { return defaultBoolean(value, false); } protected static boolean defaultBoolean(Boolean value, boolean defaultValue) { return value != null ? value : defaultValue; } protected static <T> Set<T> defaultSet(Set<T> set) { if (set == null) { set = Sets.newHashSet(); } return set; } protected static String asString(URI value) { return ResourceUtils.asString(value); } protected static String stringId(DataObjectRestRep value) { return ResourceUtils.stringId(value); } protected static String stringId(RelatedResourceRep ref) { return ResourceUtils.stringId(ref); } protected static List<String> stringIds(Collection<? extends DataObjectRestRep> values) { return ResourceUtils.stringIds(values); } protected static List<String> stringRefIds(Collection<? extends RelatedResourceRep> refs) { return ResourceUtils.stringRefIds(refs); } /** * RenderArgs safe method whereby the Play tags will automatically escape any labels */ protected static List<StringOption> dataObjectOptions(Collection<? extends DataObjectRestRep> values) { return dataObjectOptions(values, true, false); } protected static List<StringOption> dataObjectOptions(Collection<? extends DataObjectRestRep> values, boolean sorted, boolean escaped) { List<StringOption> options = Lists.newArrayList(); if (values != null) { for (DataObjectRestRep value : values) { String name = (escaped ? StringEscapeUtils.escapeHtml(name(value)) : name(value)); options.add(new StringOption(stringId(value), name)); } } if (sorted) { Collections.sort(options); } return options; } protected static <T extends DataObjectRestRep> void addDataObjectOptions(String name, Promise<List<T>> promise) { try { renderArgs.put(name, dataObjectOptions(promise.get())); } catch (Exception e) { Throwable cause = Common.unwrap(e); Logger.error(cause, "Failed to load '%s'", name); flash.now("error", MessagesUtils.get("ViprResourceController.failedToLoad", name, Common.getUserMessage(cause))); renderArgs.put(name, Collections.emptyList()); } } protected static void addStringOptions(String name, Promise<List<String>> promise) { try { renderArgs.put(name, StringOption.options(promise.get())); } catch (Exception e) { Throwable cause = Common.unwrap(e); Logger.error(cause, "Failed to load '%s'", name); flash.now("error", MessagesUtils.get("ViprResourceController.failedToLoad", name, Common.getUserMessage(cause))); renderArgs.put(name, Collections.emptyList()); } } protected static List<StringOption> namedRefOptions(Collection<? extends NamedRelatedResourceRep> refs) { return namedRefOptions(refs, true); } protected static List<StringOption> namedRefOptions(Collection<? extends NamedRelatedResourceRep> refs, boolean sorted) { List<StringOption> options = Lists.newArrayList(); if (refs != null) { for (NamedRelatedResourceRep ref : refs) { options.add(new StringOption(stringId(ref), name(ref))); } } if (sorted) { Collections.sort(options); } return options; } protected static String actionUrl(Class<? extends Controller> controller, String action, String argName, Object argValue) { return actionUrl(controller.getSimpleName() + "." + action, argName, argValue); } protected static String actionUrl(String action, String argName, Object argValue) { Map<String, Object> args = Maps.newHashMap(); if (argName != null) { args.put(argName, argValue); } return Router.reverse(action, args).url; } protected static String actionUrl(String action) { return actionUrl(action, null, null); } protected static String actionUrl(Class<? extends Controller> controller, String action) { return actionUrl(controller, action, null, null); } protected static <T, V> List<OperationResult<T, V>> getSuccessResults(List<OperationResult<T, V>> results) { List<OperationResult<T, V>> success = Lists.newArrayList(); for (OperationResult<T, V> result : results) { if (result.isSuccess()) { success.add(result); } } return success; } protected static <T, V> List<OperationResult<T, V>> getFailedResults(List<OperationResult<T, V>> results) { List<OperationResult<T, V>> failed = Lists.newArrayList(); for (OperationResult<T, V> result : results) { if (!result.isSuccess()) { failed.add(result); } } return failed; } protected static <T, V> List<T> resultValues(List<OperationResult<T, V>> results) { List<T> values = Lists.newArrayList(); for (OperationResult<T, V> result : results) { values.add(result.getValue()); } return values; } protected static <T, V> List<V> resultArgs(List<OperationResult<T, V>> results) { List<V> args = Lists.newArrayList(); for (OperationResult<T, V> result : results) { args.add(result.getArg()); } return args; } protected static <T, V> List<String> errorMessages(List<OperationResult<T, V>> results) { List<String> messages = Lists.newArrayList(); for (OperationResult<T, V> result : results) { if (!result.isSuccess()) { messages.add(result.getErrorMessage()); } } return messages; } protected static <T, V> OperationResult<T, V> perform(V arg, ResourceOperation<T, V> operation) { try { T result = operation.performOperation(arg); return new OperationResult<T, V>(arg, result); } catch (Exception e) { Logger.error(e, Common.getUserMessage(e)); return new OperationResult<T, V>(arg, e); } } protected static <T, V> List<OperationResult<T, V>> perform(List<V> args, ResourceOperation<T, V> operation) { List<OperationResult<T, V>> results = Lists.newArrayList(); for (V arg : args) { OperationResult<T, V> result = perform(arg, operation); results.add(result); } return results; } protected static <T> List<OperationResult<T, URI>> perform(String[] ids, ResourceIdOperation<T> operation) { if (ids != null) { return perform(uris(ids), operation); } else { return Lists.newArrayList(); } } protected static <T, V> void performListJson(List<V> values, ResourceOperation<T, V> operation) { List<OperationResult<T, V>> results = perform(values, operation); List<T> items = resultValues(getSuccessResults(results)); String errorMessage = StringUtils.join(errorMessages(results), "\n"); renderJSON(DataTablesSupport.createJSON(items, params, errorMessage)); } protected static <T, V> void performItemsJson(List<V> values, ResourceOperation<T, V> operation) { List<OperationResult<T, V>> results = perform(values, operation); List<T> items = resultValues(getSuccessResults(results)); renderJSON(items); } /** * Performs an operation on a list of values and logs successes. * * @param values * the values for the operation. * @param operation * the operation to run. * @param successKey * the success message key. */ protected static <T, V> void performSuccess(List<V> values, ResourceOperation<T, V> operation, String successKey) { List<OperationResult<T, V>> results = perform(values, operation); List<OperationResult<T, V>> success = getSuccessResults(results); if (!success.isEmpty()) { flash.success(MessagesUtils.get(successKey, success.size(), results.size())); } } /** * Performs an operation on a list of values and logs success/failures. * * @param values * the values for the operation. * @param operation * the operation to run. * @param successKey * the success message key. * @param failedKey * the failed message key. */ protected static <T, V> void performSuccessFail(List<V> values, ResourceOperation<T, V> operation, String successKey, String failedKey) { List<OperationResult<T, V>> results = perform(values, operation); List<OperationResult<T, V>> failed = getFailedResults(results); if (failed.isEmpty()) { flash.success(MessagesUtils.get(successKey, results.size(), results.size())); } else { int total = results.size(); int success = total - failed.size(); String errorMessage = StringUtils.join(errorMessages(results), "\n"); flash.error(MessagesUtils.get(failedKey, success, total, errorMessage)); } } public static interface ResourceOperation<T, V> { public T performOperation(V arg) throws Exception; } /** * Operation on a resource by ID. * * @param <T> * the result type. */ public static interface ResourceIdOperation<T> extends ResourceOperation<T, URI> { } /** * Operation on a resource by value. * * @param <T> * the result type * @param <V> * the value type. */ public static interface ResourceValueOperation<T, V extends DataObjectRestRep> extends ResourceOperation<T, V> { } public static class OperationResult<T, V> { private V arg; private T value; private Exception error; public OperationResult(V arg, T value) { this.arg = arg; this.value = value; } public OperationResult(V arg, Exception error) { this.arg = arg; this.error = error; } public boolean isSuccess() { return error == null; } public boolean isFailure() { return error != null; } public V getArg() { return arg; } public T getValue() { return value; } public Exception getError() { return error; } public String getErrorMessage() { return Common.getUserMessage(error); } } protected static JsonObject getCookieAsJson(String cookieKey) { try { Http.Cookie cookie = request.cookies.get(cookieKey); JsonElement jelement = new JsonParser().parse(URLDecoder.decode(cookie.value, "UTF-8")); return jelement.getAsJsonObject(); } catch (Exception e) { Logger.error(e, "Failed to load '%s'", cookieKey); return new JsonObject(); } } @SuppressWarnings("deprecation") protected static void saveJsonAsCookie(String cookieKey,JsonObject jobject) { response.setCookie(cookieKey, URLEncoder.encode(jobject.toString())); } }