/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package controllers.catalog; import static com.emc.vipr.client.core.util.ResourceUtils.uri; import java.io.Serializable; import java.util.Collections; import java.util.List; import java.util.Map; import controllers.security.Security; import models.BreadCrumb; import org.apache.commons.lang.StringUtils; import play.Logger; import play.cache.Cache; import play.mvc.Controller; import play.mvc.Util; import play.mvc.With; import util.CatalogCategoryUtils; import util.CatalogServiceUtils; import util.DocUtils; import com.emc.storageos.model.RelatedResourceRep; import com.emc.vipr.model.catalog.CatalogCategoryRestRep; import com.emc.vipr.model.catalog.CatalogServiceRestRep; import com.emc.vipr.model.catalog.ServiceDescriptorRestRep; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import controllers.Common; import controllers.tenant.TenantSelector; import controllers.util.Models; @With(Common.class) public class ServiceCatalog extends Controller { private static final String SERVICE_CATALOG = "SERVICE_CATALOG"; private static final String CATALOG_EXPIRE = "10min"; public static void view() { Map<String, CategoryDef> catalog = getCatalog(Models.currentAdminTenant()); Map<String, List<BreadCrumb>> breadcrumbs = createBreadCrumbs(catalog); TenantSelector.addRenderArgs(); render(catalog, breadcrumbs); } public static void docCategory(String categoryId) { if (categoryId == null) { redirect(DocUtils.getDocumentationLink()); } CatalogCategoryRestRep category = CatalogCategoryUtils.getCatalogCategory(uri(categoryId)); if (category == null) { redirect(DocUtils.getDocumentationLink()); } Logger.debug("Redirecting to doc page for category: " + category.getName()); // NOSONAR // ("Suppressing Sonar violation of Possible null pointer deference of category. In the previous if condition, category being null is handled.") redirect(DocUtils.getCatalogDocumentationLink(category.getName())); } @Util public static CategoryDef getCatalogRoot(String tenantId) { Map<String, CategoryDef> catalog = getCatalog(tenantId); for (CategoryDef categoryDef : catalog.values()) { if (categoryDef.parentId == null) { return categoryDef; } } return null; } @Util public static void catalogModified(String tenantId) { String cacheKey = SERVICE_CATALOG + "." + tenantId + "." + Security.getUserInfo().getIdentifier(); Cache.delete(cacheKey); } @Util public static Map<String, CategoryDef> getCatalog(String tenantId) { // change service catalog cache from by tenant to by tenant_user, as based on user's // roles and ACLs of every catalog, different users will have different views. String cacheKey = SERVICE_CATALOG + "." + tenantId + "." + Security.getUserInfo().getIdentifier(); Map<String, CategoryDef> catalog = (Map<String, CategoryDef>) Cache.get(cacheKey); if (catalog == null) { Logger.debug("Creating catalog cache for " + cacheKey); catalog = createCatalog(tenantId); Cache.set(cacheKey, catalog, CATALOG_EXPIRE); } else { Logger.debug("Using catalog from cache for " + cacheKey); } return catalog; } private static Map<String, CategoryDef> createCatalog(String tenantId) { Map<String, CategoryDef> catalog = Maps.newLinkedHashMap(); CategoryDef root = createCategory(CatalogCategoryUtils.getRootCategory(uri(tenantId)), null); addCategories(root, catalog); return catalog; } private static void addCategories(CategoryDef category, Map<String, CategoryDef> catalog) { catalog.put(category.id, category); for (CategoryDef subCategory : category.categories) { addCategories(subCategory, catalog); } } private static CategoryDef createCategory(CatalogCategoryRestRep category, String path) { CategoryDef def = new CategoryDef(); def.id = category.getId().toString(); def.name = category.getName(); def.title = category.getTitle(); def.description = category.getDescription(); def.image = category.getImage(); def.parentId = getParentId(category.getCatalogCategory()); def.path = getPath(path, def.name); List<CatalogServiceRestRep> catalogServices = CatalogServiceUtils.getCatalogServices(category); for (CatalogServiceRestRep catalogService : catalogServices) { def.services.add(createService(catalogService, def.path)); } List<CatalogCategoryRestRep> subCategories = CatalogCategoryUtils.getCatalogCategories(category); for (CatalogCategoryRestRep subCategory : subCategories) { def.categories.add(createCategory(subCategory, def.path)); } return def; } public static ServiceDef createService(CatalogServiceRestRep service, String basePath) { ServiceDescriptorRestRep descriptor = service.getServiceDescriptor(); ServiceDef def = new ServiceDef(); def.id = service.getId().toString(); def.name = service.getName(); def.title = service.getTitle(); def.description = service.getDescription(); def.roles = descriptor != null ? descriptor.getRoles() : Collections.<String> emptyList(); def.image = service.getImage(); def.parentId = getParentId(service.getCatalogCategory()); def.path = getPath(basePath, def.name); return def; } protected static String getParentId(RelatedResourceRep parentId) { if (parentId != null && parentId.getId() != null) { return parentId.getId().toString(); } return null; } protected static String getPath(String basePath, String name) { if (StringUtils.isNotBlank(basePath)) { return basePath + "/" + name; } else { return name; } } /** * Creates the breadcrumbs for the entire catalog. * * @param catalog * the service catalog. * @return the mapping of category ID to breadcrumb list. */ @Util public static Map<String, List<BreadCrumb>> createBreadCrumbs(Map<String, CategoryDef> catalog) { Map<String, List<BreadCrumb>> catalogBreadcrumbs = Maps.newLinkedHashMap(); for (CategoryDef category : catalog.values()) { List<BreadCrumb> breadcrumbs = createBreadCrumbs(category.id, catalog); catalogBreadcrumbs.put(category.id, breadcrumbs); } return catalogBreadcrumbs; } /** * Creates the breadcrumbs for the catalog service. * * @param service * the catalog service. * @return the breadcrumb list. */ @Util public static List<BreadCrumb> createBreadCrumbs(String tenantId, CatalogServiceRestRep service) { RelatedResourceRep categoryId = service.getCatalogCategory(); String parentId = getParentId(categoryId); List<BreadCrumb> breadcrumbs = createBreadCrumbs(parentId, getCatalog(tenantId)); String id = service.getId() != null ? service.getId().toString() : ""; addBreadCrumb(breadcrumbs, id, service.getName(), service.getTitle()); return breadcrumbs; } /** * Creates the breadcrumbs for the catalog category. * * @param category * the catalog category. * @return the breacrumb list. */ @Util public static List<BreadCrumb> createBreadCrumbs(String tenantId, CatalogCategoryRestRep category) { return createBreadCrumbs(category.getId().toString(), getCatalog(tenantId)); } /** * Adds a breadcrumb to the end of the list, constructing its path based on the breadcrumb at the end of the list. * * @param breadcrumbs * the list of breadcrumbs. * @param id * the breadcrumb ID. * @param name * the breadcrumb name, used to construct the path. * @param title * the breadcrumb title. */ @Util public static void addBreadCrumb(List<BreadCrumb> breadcrumbs, String id, String name, String title) { String path = getPath(getLastPath(breadcrumbs), name); breadcrumbs.add(new BreadCrumb(id, name, title, path)); } /** * Adds a simple breadcrumb with a title only. This should only ever be used to add a final breadcrumb for display * purposes. * * @param breadcrumbs * the breadcrumbs. * @param title * the breadcrumb title. */ @Util public static void addBreadCrumb(List<BreadCrumb> breadcrumbs, String title) { breadcrumbs.add(new BreadCrumb("", "", title, "")); } /** * Gets the last path entry from the breadcrumb list. * * @param breadcrumbs * the breadcrumbs. * @return the last path or empty string if there are no breadcrumbs. */ private static String getLastPath(List<BreadCrumb> breadcrumbs) { if (!breadcrumbs.isEmpty()) { return breadcrumbs.get(breadcrumbs.size() - 1).path; } else { return ""; } } /** * Creates a breadcrumb list for the given category. * * @param categoryId * the ID of the category to create the breadcrumb for. * @param catalog * the catalog. * @return the breadcrumb list. */ @Util public static List<BreadCrumb> createBreadCrumbs(String categoryId, Map<String, CategoryDef> catalog) { List<BreadCrumb> breadcrumbs = Lists.newArrayList(); CategoryDef current = catalog.get(categoryId); while (current != null) { breadcrumbs.add(createBreadCrumb(current)); current = catalog.get(current.parentId); } Collections.reverse(breadcrumbs); return breadcrumbs; } @Util public static BreadCrumb createBreadCrumb(CategoryDef category) { return new BreadCrumb(category.id, category.name, category.title, category.path); } @Util public static BreadCrumb createBreadCrumb(ServiceDef service) { return new BreadCrumb(service.id, service.name, service.title, service.path); } public static class CategoryDef implements Serializable { public String id; public String name; public String title; public String description; public String image; public String parentId; public String path; public List<CategoryDef> categories = Lists.newArrayList(); public List<ServiceDef> services = Lists.newArrayList(); public CategoryDef getSubCategory(String name) { for (CategoryDef subcategory : categories) { if (subcategory.name.equals(name)) { return subcategory; } } return null; } public boolean containsSubCategory(String name) { return getSubCategory(name) != null; } public boolean containsService(String name) { for (ServiceDef service : services) { if (service.name.equals(name)) { return true; } } return false; } } public static class ServiceDef implements Serializable { public String id; public String name; public String title; public String description; public List<String> roles; public String image; public String parentId; public String path; } }