/* vim: set ts=2 et sw=2 cindent fo=qroca: */ package com.globant.katari.gadgetcontainer.application; import org.apache.commons.lang.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.json.JSONArray; import org.json.JSONObject; import org.json.JSONException; import com.globant.katari.core.application.Command; import com.globant.katari.core.application.JsonRepresentation; import com.globant.katari.gadgetcontainer.domain.ContextUserService; import com.globant.katari.gadgetcontainer.domain.GadgetGroup; import com.globant.katari.gadgetcontainer.domain.GadgetGroupTemplate; import com.globant.katari.gadgetcontainer.domain.GadgetInstance; import com.globant.katari.gadgetcontainer.domain.GadgetGroupRepository; import com.globant.katari.hibernate.coreuser.domain.CoreUser; import com.globant.katari.hibernate.coreuser.domain.CoreUserRepository; /** Looks for a gadget group by name. * * Call setGroupName() and optionally setOwnerId() before executing this * command. If you pass an owner id, this command returns the gadget group of * this user. If you do not call setOwnerId, this command returns the gadget * group of the currently logged on user. * * It generates the json representation for the gadget group. */ public class GadgetGroupCommand implements Command<JsonRepresentation> { /** The class logger. */ private static Logger log = LoggerFactory.getLogger(GadgetGroupCommand.class); /** The repository for gadget groups. * * This is never null. */ private final GadgetGroupRepository gadgetGroupRepository; /** The repository for users. * * This is never null. */ private final CoreUserRepository userRepository; /** Service used to obtain the currently logged on user. * * This is never null. */ private final ContextUserService userService; /** The open social token service implementation. * * This is never null. */ private final TokenService tokenService; /** Decides if a user can see a group he does not own. * * If null, users will only see gadget groups that they own. */ private ViewerOwnerRestriction viewerOwnerRestriction = null; /** The name of the gadget group to search, as provided by the user. */ private String groupName; /** The id of the owner of the gadget group to search. * * If this is not specified (0), the command will return the gadget group for * the currently logged on user. */ private long requestedOwnerId = 0; /** Constructor. * * @param theUserRepository Cannot be null. * * @param theGroupRepository Cannot be null. * * @param theUserService Cannot be null. * * @param theTokenService Cannot be null. * * @param restriction decides if the user can see a gadget group that he * doesn't own. If null, users will only see their own gadget groups. */ public GadgetGroupCommand(final CoreUserRepository theUserRepository, final GadgetGroupRepository theGroupRepository, final ContextUserService theUserService, final TokenService theTokenService, final ViewerOwnerRestriction restriction) { Validate.notNull(theUserRepository, "user repository cannot be null"); Validate.notNull(theGroupRepository, "gadget repository cannot be null"); Validate.notNull(theUserService, "user service cannot be null"); Validate.notNull(theTokenService, "token service cannot be null"); userRepository = theUserRepository; gadgetGroupRepository = theGroupRepository; userService = theUserService; tokenService = theTokenService; viewerOwnerRestriction = restriction; } /** The name of the group to search for, as provided by the user. * * @param name the groupName to set. It must be called with a non empty * string before calling execute. */ public void setGroupName(final String name) { groupName = name; } /** The id of the user that owns the group to search for. * * @param id the user id. It cannot be 0. */ public void setOwnerId(final long id) { Validate.isTrue(id != 0, "The owner id cannot be 0."); requestedOwnerId = id; } /** Find the group with the given group name for the currently logged in * user. * * Call setGroupName with a non empty string before calling execute. * * The json structure is: * * <pre> * { * "id":<long>, * "name":"<string>" * "ownerId":<long>, * "viewerId":<long>, * "view":"<string>", * "numberOfColumns":<int>, * "customizable":<true|false>, * "gadgets":[ * { * "id":<long>, * "title":<string>, * "appId":<long>, * "column":<int>, * "order":<int>, * "securityToken":"token" * "url":"url" * } * ], * } * </pre> * * If the gadget was not found, it returns an empty json object ({}). * * @return a json object, never returns null. */ public JsonRepresentation execute() { log.trace("Entering execute"); Validate.notEmpty(groupName, "groupName cannot be blank"); // The viewer of the group. It can be an anonymous user, so getCurrentUser // may return null. CoreUser viewer = userService.getCurrentUser(); long viewerId = 0; if (viewer != null) { viewerId = viewer.getId(); } long ownerId = viewerId; if (requestedOwnerId != 0) { ownerId = requestedOwnerId; } log.debug("Searching group = " + groupName + " for the user:" + ownerId); GadgetGroup group; group = gadgetGroupRepository.findGadgetGroup(ownerId, groupName); if (group == null) { // Group not found, it could be because the user id is invalid. CoreUser owner = null; if (requestedOwnerId != 0) { owner = userRepository.findUser(requestedOwnerId); if (owner == null) { throw new RuntimeException("Owner not found: " + requestedOwnerId); } } else { owner = viewer; } GadgetGroupTemplate templ; templ = gadgetGroupRepository.findGadgetGroupTemplate(groupName); if (templ == null) { throw new RuntimeException("Group not found " + groupName); } group = templ.createFromTemplate(owner); gadgetGroupRepository.save(group); } if (requestedOwnerId != 0 && requestedOwnerId != viewerId) { // The user is trying to see a group he does not own. if (viewerOwnerRestriction == null) { throw new RuntimeException("Group is not accesible by user."); } if (!viewerOwnerRestriction.canView(group, requestedOwnerId, viewerId)) { throw new RuntimeException("Group is not accesible by user."); } } // The gadget group is never null here, it was found or created from a // template. JsonRepresentation result = null; try { result = new JsonRepresentation(toJson(viewerId, ownerId, group)); } catch (JSONException e) { throw new RuntimeException("Error serializing to json", e); } log.trace("Leaving execute"); return result; } /** Generates the json representation of the provided gadget group. * * @param viewerId The id of the user making the request. * * @param ownerId The id of the user that owns the gadget group. We cannot * use the gadget group owner because the group can be a shared one, where * the owner is 0. * * @param group The group to convert to json. It cannot be null. * * @return a json object that represents the gadget group. See javadoc of * execute for the json structure. * * @throws JSONException when the json object could not be generated. */ private JSONObject toJson(final long viewerId, final long ownerId, final GadgetGroup group) throws JSONException { Validate.notNull(group, "The gadget group cannot be null."); boolean isCustomizable = group.isCustomizable(); if (viewerId != ownerId || viewerId == 0) { isCustomizable = false; } JSONObject groupJson = new JSONObject(); groupJson.put("id", group.getId()); groupJson.put("name", group.getName()); groupJson.put("ownerId", ownerId); groupJson.put("viewerId", viewerId); groupJson.put("view", group.getView()); groupJson.put("numberOfColumns", group.getNumberOfColumns()); groupJson.put("customizable", isCustomizable); JSONArray gadgets = new JSONArray(); for (GadgetInstance gadget : group.getGadgets()) { JSONObject gadgetJson = new JSONObject(); gadgetJson.put("id", gadget.getId()); gadgetJson.put("title", gadget.getTitle()); gadgetJson.put("appId", gadget.getApplication().getId()); gadgetJson.put("column", gadget.getColumn()); gadgetJson.put("order", gadget.getOrder()); gadgetJson.put("icon", gadget.getApplication().getIcon()); gadgetJson.put("url", gadget.getApplication().getUrl()); String token; token = tokenService.createSecurityToken(viewerId, ownerId, gadget); gadgetJson.put("securityToken", token); gadgets.put(gadgetJson); } groupJson.put("gadgets", gadgets); return groupJson; } }