Package com.google.testing.testify.risk.frontend.server.service.impl

Source Code of com.google.testing.testify.risk.frontend.server.service.impl.ProjectServiceImpl

// Copyright 2010 Google Inc. All Rights Reseved.
//
// 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.google.testing.testify.risk.frontend.server.service.impl;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.testing.testify.risk.frontend.model.AccElementType;
import com.google.testing.testify.risk.frontend.model.AccLabel;
import com.google.testing.testify.risk.frontend.model.Attribute;
import com.google.testing.testify.risk.frontend.model.Capability;
import com.google.testing.testify.risk.frontend.model.Component;
import com.google.testing.testify.risk.frontend.model.HasLabels;
import com.google.testing.testify.risk.frontend.model.Project;
import com.google.testing.testify.risk.frontend.server.service.ProjectService;
import com.google.testing.testify.risk.frontend.server.service.UserService;
import com.google.testing.testify.risk.frontend.server.util.ServletUtils;
import com.google.testing.testify.risk.frontend.shared.rpc.UserRpc.ProjectAccess;
import com.google.testing.testify.risk.frontend.shared.util.StringUtil;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Query;

/**
* This acts as a broker for the client when accessing project information, such as Attributes and
* Components. Any operation will be checked using the user's current credentials, and fail if the
* user doesn't have access to view or edit any project information.
*
* @author chrsmith@google.com (Chris Smith)
*/
@Singleton
public class ProjectServiceImpl implements ProjectService {
  private static final Logger log = Logger.getLogger(ProjectServiceImpl.class.getName());
  private final PersistenceManagerFactory pmf;
  private final UserService userService;

  /**
   * Creates a new ProjectServiceImpl instance. Internally all methods will use the
   * PersistanceManager associated with JDOHelper.getPersistenceManagerFactory (meaning
   * jdoconfig.xml).
   */
  @Inject
  public ProjectServiceImpl(PersistenceManagerFactory pmf, UserService userService) {
    this.pmf = pmf;
    this.userService = userService;
  }

  @SuppressWarnings("unchecked")
  @Override
  public List<Project> query(String query) {
    log.info("Querying: " + query);
    PersistenceManager pm = pmf.getPersistenceManager();

    // TODO(jimr): this currently does not do a query, it just returns all public projects.
    Query jdoQuery = pm.newQuery(Project.class);
    jdoQuery.setOrdering("projectId asc");

    List<Project> results = null;
    try {
      List<Project> returnedProjects = (List<Project>) jdoQuery.execute();
      List<Project> safeToDisplayProjs = Lists.newArrayList();

      for (Project returnedProject : returnedProjects) {
        if (userService.hasViewAccess(returnedProject)) {
          safeToDisplayProjs.add(returnedProject);
        }
      }

      results = ServletUtils.makeGwtSafe(safeToDisplayProjs, pm);
      populateCachedAccess(results);
    } finally {
      pm.close();
    }

    return results;
  }

  private void populateCachedAccess(List<Project> projects) {
    for (Project p : projects) {
      populateCachedAccess(p);
    }
  }

  private void populateCachedAccess(Project p) {
    p.setCachedAccessLevel(userService.getAccessLevel(p));
  }

  /**
   * Retrieves the list of projects relevant to the currently logged in user.
   */
  @SuppressWarnings("unchecked")
  @Override
  public List<Project> queryUserProjects() {
    if (!userService.isUserLoggedIn()) {
      log.info("Querying user projects; user is not logged in.");
      return Lists.newArrayList();
    }

    log.info("Querying user projects.");
    PersistenceManager pm = pmf.getPersistenceManager();

    Query jdoQuery = pm.newQuery(Project.class);
    jdoQuery.setOrdering("projectId asc");

    List<Project> results = null;
    try {
      List<Long> starredProjects = userService.getStarredProjects();

      List<Project> returnedProjects = (List<Project>) jdoQuery.execute();
      List<Project> projectsToReturn = Lists.newArrayList();

      for (Project returnedProject : returnedProjects) {
        // Only returns the projects that are either:
        // * Starred by the user and have access (implicit or explicit).
        // * Granted VIEW or EDIT access explicitly. (Ignore public projects.)
        ProjectAccess access = userService.getAccessLevel(returnedProject);

        // If explicit, add it. Otherwise, check starred access (and implicit access).
        if (access.hasAccess(ProjectAccess.EXPLICIT_VIEW_ACCESS)) {
          projectsToReturn.add(returnedProject);
        } else if (access.hasAccess(ProjectAccess.VIEW_ACCESS)
            && starredProjects.contains(returnedProject.getProjectId())) {
          projectsToReturn.add(returnedProject);
        }
      }

      results = ServletUtils.makeGwtSafe(projectsToReturn, pm);
      populateCachedAccess(results);
    } finally {
      pm.close();
    }

    return results;
  }

  /**
   * Returns the list of projects the currently logged in user has EDIT access to.
   */
  @Override
  public List<Project> queryProjectsUserHasEditAccessTo() {
    ServletUtils.requireAccess(userService.isUserLoggedIn());

    // Start with all starred projects and those granting explicit access.
    List<Project> projects = queryUserProjects();
    List<Project> projectsToReturn = Lists.newArrayList();

    for (Project project : projects) {
      if (userService.hasEditAccess(project)) {
        projectsToReturn.add(project);
      }
    }

    populateCachedAccess(projectsToReturn);
    return projectsToReturn;
  }

  @Override
  public Project getProjectById(long id) {
    log.info("Getting project: " + Long.toString(id));

    PersistenceManager pm = pmf.getPersistenceManager();
    try {
      Project retrievedProject = pm.getObjectById(Project.class, id);
      // Don't disclose that the project even exists if they don't have view access.
      if (retrievedProject != null && userService.hasViewAccess(retrievedProject)) {
        retrievedProject = ServletUtils.makeGwtSafe(retrievedProject, pm);
        populateCachedAccess(retrievedProject);
        return retrievedProject;
      }
    } finally {
      pm.close();
    }
    return null;
  }

  @Override
  @SuppressWarnings("unchecked")
  public Project getProjectByName(String name) {
    log.info("Getting project with name: " + name);

    PersistenceManager pm = pmf.getPersistenceManager();

    Query jdoQuery = pm.newQuery(Project.class);
    jdoQuery.declareParameters("String projectNameParam");
    jdoQuery.setFilter("name == projectNameParam");

    try {
      List<Project> returnedProjects = (List<Project>) jdoQuery.execute(name);
      log.info(String.format("Found %s projects with name %s", returnedProjects.size(), name));

      for (Project target : returnedProjects) {
        if (userService.hasViewAccess(target)) {
          target = ServletUtils.makeGwtSafe(target, pm);
          populateCachedAccess(target);
          return target;
        }
      }
    } finally {
      pm.close();
    }
    return null;
  }

  @Override
  public Long createProject(Project projInfo) {
    // The user must be logged in to create a project.
    ServletUtils.requireAccess(userService.isUserLoggedIn());
    log.info("Creating new Project with name: " + projInfo.getName());

    if (projInfo.getProjectId() != null) {
      throw new IllegalArgumentException(
          "You can only create a project with a null ID.");
    }

    PersistenceManager pm = pmf.getPersistenceManager();
    try {
      // Automatically add the current user as an OWNER for the project.
      projInfo.addProjectOwner(userService.getEmail());
      pm.makePersistent(projInfo);
    } finally {
      pm.close();
    }

    return projInfo.getProjectId();
  }

  @Override
  public void updateProject(Project projInfo) {
    if (projInfo.getProjectId() == null) {
      throw new IllegalArgumentException(
          "projInfo has not been saved. Please call createProject first.");
    }
    ServletUtils.requireAccess(userService.hasEditAccess(projInfo.getProjectId()));

    log.info("Updating Project: " + projInfo.getProjectId().toString());
    PersistenceManager pm = pmf.getPersistenceManager();
    Project oldProject;
    try {
      oldProject = pm.getObjectById(Project.class, projInfo.getProjectId());
      List<String> oldOwners = oldProject.getProjectOwners();
      List<String> oldEditors = oldProject.getProjectEditors();
      List<String> oldViewers = oldProject.getProjectViewers();

      // If they're not an owner, keep the old list of owners around.
      if (!userService.hasOwnerAccess(projInfo.getProjectId())) {
        projInfo.setIsPubliclyVisible(oldProject.getIsPubliclyVisible());
        projInfo.setProjectOwners(oldProject.getProjectOwners());
      }

      pm.makePersistent(projInfo);

      log.info("Notifying users of any changes to access level");
      String from = userService.getEmail();
      List<String> added = StringUtil.subtractList(projInfo.getProjectOwners(),
          oldOwners);
      if (added.size() > 0) {
        ServletUtils.notifyAddedAccess(from, added, "owner", projInfo.getName(),
            projInfo.getProjectId().toString());
      }
      List<String> removed = StringUtil.subtractList(oldOwners, projInfo.getProjectOwners());
      if (removed.size() > 0) {
          ServletUtils.notifyRemovedAccess(from, removed, "owner", projInfo.getName(),
            projInfo.getProjectId().toString());
      }

      added = StringUtil.subtractList(projInfo.getProjectEditors(), oldEditors);
      if (added.size() > 0) {
        ServletUtils.notifyAddedAccess(from, added, "editor", projInfo.getName(),
            projInfo.getProjectId().toString());
      }
      removed = StringUtil.subtractList(oldEditors, projInfo.getProjectEditors());
      if (removed.size() > 0) {
        ServletUtils.notifyRemovedAccess(from, removed, "editor", projInfo.getName(),
            projInfo.getProjectId().toString());
      }

      added = StringUtil.subtractList(projInfo.getProjectViewers(), oldViewers);
      if (added.size() > 0) {
        ServletUtils.notifyAddedAccess(from, added, "viewer", projInfo.getName(),
            projInfo.getProjectId().toString());
      }
      removed = StringUtil.subtractList(oldViewers, projInfo.getProjectViewers());
      if (removed.size() > 0) {
        ServletUtils.notifyRemovedAccess(from, removed, "viewer", projInfo.getName(),
            projInfo.getProjectId().toString());
      }
    } finally {
      pm.close();
    }
  }

  @Override
  public void removeProject(Project projInfo) {
    if (projInfo.getProjectId() == null) {
      log.info("Attempting to delete unsaved project. Ignoring.");
      return;
    }
    ServletUtils.requireAccess(userService.hasOwnerAccess(projInfo.getProjectId()));

    PersistenceManager pm = pmf.getPersistenceManager();
    try {
      Project projToDelete = pm.getObjectById(Project.class, projInfo.getProjectId());

      // TODO(jimr): This delete could succeed but successive removes might fail, leaving dangling
      // data.  We should retry or do something to assure complete destruction.

      // TODO(jimr): Undo?
      pm.deletePersistent(projToDelete);

      // Delete any child attributes, components, or capabilities.
      removeObjectsWithFieldValue(pm, Attribute.class, "parentProjectId", projInfo.getProjectId());
      removeObjectsWithFieldValue(pm, Component.class, "parentProjectId", projInfo.getProjectId());
      removeObjectsWithFieldValue(pm, Capability.class, "parentProjectId", projInfo.getProjectId());

      // TODO(chrsmith): What about enabled data providers? For example, bugs or checkin data
      // associated with this project? We need to clear those out as well.
    } finally {
      pm.close();
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  public List<AccLabel> getLabels(long projectId) {
    ServletUtils.requireAccess(userService.hasViewAccess(projectId));

    log.info("Getting labels for project: " + Long.toString(projectId));
    PersistenceManager pm = pmf.getPersistenceManager();

    Query jdoQuery = pm.newQuery(AccLabel.class);
    jdoQuery.setFilter("projectId == projectIdParam");
    jdoQuery.declareParameters("Long projectIdParam");

    try {
      List<AccLabel> labels = (List<AccLabel>) jdoQuery.execute(projectId);
      return ServletUtils.makeGwtSafe(labels, pm);
    } finally {
      pm.close();
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  public List<Attribute> getProjectAttributes(long projectId) {
    ServletUtils.requireAccess(userService.hasViewAccess(projectId));

    log.info("Getting Attributes for project: " + Long.toString(projectId));
    PersistenceManager pm = pmf.getPersistenceManager();

    Query jdoQuery = pm.newQuery(Attribute.class);
    jdoQuery.setFilter("parentProjectId == parentProjectParam");
    jdoQuery.setOrdering("displayOrder asc");
    jdoQuery.declareParameters("Long parentProjectParam");

    try {
      List<Attribute> returnedAttributes = (List<Attribute>) jdoQuery.execute(projectId);
      returnedAttributes = ServletUtils.makeGwtSafe(returnedAttributes, pm);
      populateLabels(returnedAttributes, pm);
      return returnedAttributes;
    } finally {
      pm.close();
    }
  }

  /**
   * Populates labels for a HasLabels item.
   *
   * @param <T> An object that HasLabels.
   * @param item The item to get labels for.
   * @param pm A persistence manager object.
   */
  private <T extends HasLabels> void populateLabels(T item, PersistenceManager pm) {
    item.setAccLabels(getLabelsForItem(item, pm));
  }

  /**
   * Populates labels for a list of HasLabels items.  All items MUST be for the same project
   * and of the same type (ie, all Attributes).
   *
   * IMPORTANT: you probably want to detach your object before calling this.
   *
   * @param <T> An object that HasLabels.
   * @param items The items to get labels for.
   * @param pm A persistence manager object.
   */
  @SuppressWarnings("unchecked")
  private <T extends HasLabels> void populateLabels(List<T> items, PersistenceManager pm) {
    if (items.size() > 0) {
      Map<Long, T> idToItem = Maps.newHashMap();
      for (T item : items) {
        idToItem.put(item.getId(), item);
      }
      T item = items.get(0);
      AccElementType type = item.getElementType();
      Long parentProjectId = item.getParentProjectId();
      Query query = pm.newQuery(AccLabel.class);
      query.declareParameters("AccElementType elementTypeParam, Long projectIdParam");
      query.setFilter("elementType == elementTypeParam && projectId == projectIdParam");
      List<AccLabel> labels = (List<AccLabel>) query.execute(type, parentProjectId);
      log.info("Found labels: " + labels.size());

      for (AccLabel label : labels) {
        item = idToItem.get(label.getElementId());
        if (item != null) {
          log.info("Putting label where it belongs: " + label.getLabelText());
          item.addLabel(label);
        }
      }
    }
  }

  @SuppressWarnings("unchecked")
  private <T extends HasLabels> List<AccLabel> getLabelsForItem(T item, PersistenceManager pm) {
    Query query = pm.newQuery(AccLabel.class);
    query.declareParameters(
        "AccElementType elementTypeParam, Long elementIdParam, Long projectIdParam");
    query.setFilter("elementType == elementTypeParam && elementId == elementIdParam && "
        + "projectId == projectIdParam");
    List<AccLabel> labels = (List<AccLabel>) query.execute(item.getElementType(), item.getId(),
        item.getParentProjectId());
    // This constructs a new, real list -- the list returned by the above execution is a lazy-loaded
    // streaming query.  That doesn't serialize.
    return Lists.newArrayList(labels);
  }

  /**
   * Saves labels for an item.
   *
   * This is not extremely necessary, but for simplicity ('always call persistLabels') it's here.
   *
   * @param <T> An object that HasLabels.
   * @param item The item to save the labels for.
   * @param pm A persistence mananger.
   */
  private <T extends HasLabels> void persistLabels(T item, PersistenceManager pm) {
    List<AccLabel> toDelete = Lists.newArrayList();
    Set<String> newLabelKeys = Sets.newHashSet();
    for (AccLabel label : item.getAccLabels()) {
      if (label.getId() != null) {
        newLabelKeys.add(label.getId());
      }
    }

    List<AccLabel> currentLabels = getLabelsForItem(item, pm);
    for (AccLabel label : currentLabels) {
      if (!newLabelKeys.contains(label.getId())) {
        toDelete.add(label);
      }
    }
    pm.deletePersistentAll(toDelete);
    // And add the new ones.
    pm.makePersistentAll(item.getAccLabels());
  }


  private <T extends HasLabels> void updateLabelElementIds(T item, Long id) {
    for (AccLabel label : item.getAccLabels()) {
      label.setElementId(id);
    }
  }

  private <T extends HasLabels> void deleteLabels(T item, PersistenceManager pm) {
    pm.deletePersistentAll(item.getAccLabels());
  }

  @Override
  public Long createAttribute(Attribute attribute) {
    ServletUtils.requireAccess(userService.hasEditAccess(attribute.getParentProjectId()));

    if (attribute.getAttributeId() != null) {
      throw new IllegalArgumentException(
          "You can only create an attribute with a null ID.");
    }

    log.info("Creating new Attribute with name: " + attribute.getName());
    attribute.setName(attribute.getName().trim());

    PersistenceManager pm = pmf.getPersistenceManager();
    try {
      pm.makePersistent(attribute);

      // If we have labels, update their element ID now that we have an ID.
      if (attribute.getAccLabels().size() > 0) {
        pm.close();
        updateLabelElementIds(attribute, attribute.getAttributeId());
        pm = pmf.getPersistenceManager();
        persistLabels(attribute, pm);
      }
    } finally {
      pm.close();
    }

    return attribute.getAttributeId();
  }

  @Override
  public Attribute updateAttribute(Attribute attribute) {
    if (attribute.getAttributeId() == null) {
      throw new IllegalArgumentException(
          "attribute has not been saved. Please call createAttribute first.");
    }

    // Make sure they can edit the project into which they are trying to save.
    ServletUtils.requireAccess(userService.hasEditAccess(attribute.getParentProjectId()));

    log.info("Updating Attribute: " + attribute.getAttributeId().toString());
    PersistenceManager pm = pmf.getPersistenceManager();
    try {
      Attribute oldAttribute = pm.getObjectById(Attribute.class, attribute.getAttributeId());
      if (oldAttribute.getParentProjectId() != attribute.getParentProjectId()) {
        log.severe("Possible attack -- attribute sent in and attribute being overwritten had"
            + " different project IDs.");
        ServletUtils.requireAccess(false);
      }

      persistLabels(attribute, pm);
      pm.makePersistent(attribute);
      attribute = ServletUtils.makeGwtSafe(attribute, pm);
      populateLabels(attribute, pm);
      attribute.setAccLabels(ServletUtils.makeGwtSafe(attribute.getAccLabels(), pm));
      return attribute;
    } finally {
      pm.close();
    }
  }

  @Override
  public void removeAttribute(Attribute attribute) {
    if (attribute.getAttributeId() == null) {
      log.info("Attempting to delete unsaved Attribute. Ignoring.");
      return;
    }

    log.info("Removing Attribute: " + attribute.getAttributeId().toString());
    PersistenceManager pm = pmf.getPersistenceManager();
    try {
      Attribute attributeToDelete = pm.getObjectById(Attribute.class, attribute.getAttributeId());
      ServletUtils.requireAccess(userService.hasEditAccess(attributeToDelete.getParentProjectId()));

      pm.deletePersistent(attributeToDelete);
      deleteLabels(attribute, pm);

      // Delete any child capabilities.
      removeObjectsWithFieldValue(pm, Capability.class, "attributeId", attribute.getAttributeId());
    } finally {
      pm.close();
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  public void reorderAttributes(long projectId, List<Long> newOrdering) {
    log.info("Reordering Attributes for project: " + Long.toString(projectId));
    Function<Attribute, Long> getId = new Function<Attribute, Long>() {
      @Override
      public Long apply(Attribute input) {
        return input.getAttributeId();
      }
    };
    Setter<Attribute> setId = new Setter<Attribute>() {
      @Override
      public boolean apply(Attribute input, long value) {
        if (input.getDisplayOrder() != value) {
          input.setDisplayOrder(value);
          return true;
        }
        return false;
      }
    };
    setOrder(projectId, Attribute.class, newOrdering, getId, setId);
  }

  @SuppressWarnings("unchecked")
  @Override
  public List<Component> getProjectComponents(long projectId) {
    ServletUtils.requireAccess(userService.hasViewAccess(projectId));

    log.info("Getting Components for project: " + Long.toString(projectId));
    PersistenceManager pm = pmf.getPersistenceManager();

    Query jdoQuery = pm.newQuery(Component.class);
    jdoQuery.setFilter("parentProjectId == parentProjectParam");
    jdoQuery.setOrdering("displayOrder asc");
    jdoQuery.declareParameters("Long parentProjectParam");

    try {
      List<Component> returnedComponents = (List<Component>) jdoQuery.execute(projectId);
      returnedComponents = ServletUtils.makeGwtSafe(returnedComponents, pm);
      populateLabels(returnedComponents, pm);
      return returnedComponents;
    } finally {
      pm.close();
    }
  }

  @Override
  public Long createComponent(Component component) {
    ServletUtils.requireAccess(userService.hasEditAccess(component.getParentProjectId()));

    if (component.getComponentId() != null) {
      throw new IllegalArgumentException(
          "You can only create a component with a null ID.");
    }

    log.info("Creating new Component with name: " + component.getName());
    component.setName(component.getName().trim());

    PersistenceManager pm = pmf.getPersistenceManager();
    try {
      pm.makePersistent(component);

      // If we have labels, update their element ID now that we have an ID.
      if (component.getAccLabels().size() > 0) {
        pm.close();
        updateLabelElementIds(component, component.getId());
        pm = pmf.getPersistenceManager();
        persistLabels(component, pm);
      }
    } finally {
      pm.close();
    }

    return component.getComponentId();
  }

  @Override
  public Component updateComponent(Component component) {
    if (component.getComponentId() == null) {
      throw new IllegalArgumentException(
          "component has not been saved. Please call createComponent first.");
    }

    // Make sure they can edit the project into which they are trying to save.
    ServletUtils.requireAccess(userService.hasEditAccess(component.getParentProjectId()));

    log.info("Updating Component: " + component.getComponentId().toString());
    PersistenceManager pm = pmf.getPersistenceManager();
    try {
      Component oldComponent = pm.getObjectById(Component.class, component.getComponentId());
      if (oldComponent.getParentProjectId() != component.getParentProjectId()) {
        log.severe("Possible attack -- component sent in and component being overwritten had"
            + " different project IDs.");
        ServletUtils.requireAccess(false);
      }

      persistLabels(component, pm);
      pm.makePersistent(component);
      component = ServletUtils.makeGwtSafe(component, pm);
      populateLabels(component, pm);
      component.setAccLabels(ServletUtils.makeGwtSafe(component.getAccLabels(), pm));
      return component;
    } finally {
      pm.close();
    }
  }

  @Override
  public void removeComponent(Component component) {
    if (component.getComponentId() == null) {
      log.info("Attempting to delete unsaved Component. Ignoring.");
      return;
    }

    log.info("Removing Component: " + component.getComponentId().toString());
    PersistenceManager pm = pmf.getPersistenceManager();
    try {
      Component componentToDelete = pm.getObjectById(Component.class, component.getComponentId());
      ServletUtils.requireAccess(userService.hasEditAccess(componentToDelete.getParentProjectId()));

      pm.deletePersistent(componentToDelete);
      deleteLabels(componentToDelete, pm);

      // Delete any child capabilities.
      removeObjectsWithFieldValue(pm, Capability.class, "componentId", component.getComponentId());
    } finally {
      pm.close();
    }
  }

  @SuppressWarnings("unchecked")
  private <T> void setOrder(long projectId, Class<T> clazz, List<Long> order,
      Function<T, Long> getId, Setter<T> applyOrder) {
    log.info("setOrder executing with " + order.size() + " items passed in.");
    ServletUtils.requireAccess(userService.hasEditAccess(projectId));

    PersistenceManager pm = pmf.getPersistenceManager();
    try {
      Query jdoQuery = pm.newQuery(clazz);
      jdoQuery.setFilter("parentProjectId == parentProjectParam");
      jdoQuery.declareParameters("Long parentProjectParam");
      List<T> items = (List<T>) jdoQuery.execute(projectId);

      Map<Long, Integer> lookup = Maps.newHashMap();
      for (int i = 0; i < order.size(); i++) {
        Long id = order.get(i);
        lookup.put(id, i);
      }
      for (T item : items) {
        Long id = getId.apply(item);
        Integer newIndex = lookup.get(id);
        if (newIndex != null) {
          if (applyOrder.apply(item, newIndex)) {
            pm.makePersistent(item);
          }
        } else {
          log.warning("Project contains item not covered in new ordering - ID: " + id);
        }
      }
    } finally {
      pm.close();
    }
    log.info("setOrder complete");
  }

  @Override
  public void reorderCapabilities(long projectId, List<Long> newOrdering) {
    log.info("Reordering capabilities for project: " + Long.toString(projectId));
    Function<Capability, Long> getId = new Function<Capability, Long>() {
      @Override
      public Long apply(Capability input) {
        return input.getCapabilityId();
      }
    };
    Setter<Capability> setId = new Setter<Capability>() {
      @Override
      public boolean apply(Capability input, long value) {
        if (input.getDisplayOrder() != value) {
          input.setDisplayOrder(value);
          return true;
        }
        return false;
      }
    };
    setOrder(projectId, Capability.class, newOrdering, getId, setId);
  }

  @SuppressWarnings("unchecked")
  @Override
  public void reorderComponents(long projectId, List<Long> newOrdering) {
    log.info("Reordering Components for project: " + Long.toString(projectId));
    Function<Component, Long> getId = new Function<Component, Long>() {
      @Override
      public Long apply(Component input) {
        return input.getComponentId();
      }
    };
    Setter<Component> setId = new Setter<Component>() {
      @Override
      public boolean apply(Component input, long value) {
        if (input.getDisplayOrder() != value) {
          input.setDisplayOrder(value);
          return true;
        }
        return false;
      }
    };
    setOrder(projectId, Component.class, newOrdering, getId, setId);
  }

  private interface Setter<F> {
    boolean apply(F input, long value);
  }

  @Override
  @SuppressWarnings("unchecked")
  public Capability getCapabilityById(long projectId, long capabilityId) {
    ServletUtils.requireAccess(userService.hasViewAccess(projectId));
    log.info("Getting capability for project by id: " + Long.toString(projectId) + ", "
        + Long.toString(capabilityId));
    PersistenceManager pm = pmf.getPersistenceManager();

    Query jdoQuery = pm.newQuery(Capability.class);
    jdoQuery.setFilter(
        "parentProjectId == parentProjectParam && capabilityId == capabilityIdParam");
    jdoQuery.declareParameters("Long parentProjectParam, Long capabilityIdParam");
    try {
      List<Capability> results = (List<Capability>) jdoQuery.execute(
          projectId, capabilityId);
      if (results.size() > 0) {
        Capability c = results.get(0);
        c = ServletUtils.makeGwtSafe(c, pm);
        populateLabels(c, pm);
        return c;
      } else {
        return null;
      }
    } finally {
      pm.close();
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  public List<Capability> getProjectCapabilities(long projectId) {
    ServletUtils.requireAccess(userService.hasViewAccess(projectId));

    log.info("Getting Capabilities for project: " + Long.toString(projectId));
    PersistenceManager pm = pmf.getPersistenceManager();

    Query jdoQuery = pm.newQuery(Capability.class);
    jdoQuery.setFilter("parentProjectId == parentProjectParam");
    jdoQuery.setOrdering("displayOrder asc");
    jdoQuery.declareParameters("Long parentProjectParam");

    try {
      List<Capability> returnedCapabilities = (List<Capability>) jdoQuery.execute(projectId);
      returnedCapabilities = ServletUtils.makeGwtSafe(returnedCapabilities, pm);
      populateLabels(returnedCapabilities, pm);
      return returnedCapabilities;
    } finally {
      pm.close();
    }
  }

  @Override
  public Capability createCapability(Capability capability) {
    ServletUtils.requireAccess(userService.hasEditAccess(capability.getParentProjectId()));

    if (capability.getCapabilityId() != null) {
      throw new IllegalArgumentException(
          "You can only create a capability with a null ID.");
    }

    log.info("Creating new Capability with name: " + capability.getName());
    capability.setName(capability.getName().trim());

    PersistenceManager pm = pmf.getPersistenceManager();
    try {
      pm.makePersistent(capability);
      capability = ServletUtils.makeGwtSafe(capability, pm);

      // If we have labels, update their element ID now that we have an ID.
      if (capability.getAccLabels().size() > 0) {
        pm.close();
        updateLabelElementIds(capability, capability.getId());
        pm = pmf.getPersistenceManager();
        persistLabels(capability, pm);
      }
      return capability;
    } finally {
      pm.close();
    }
  }

  @Override
  public void updateCapability(Capability capability) {
    if (capability.getCapabilityId() == null) {
      throw new IllegalArgumentException(
          "Capability has not been saved. Please call createCapability first.");
    }

    // Make sure they can edit the project into which they are trying to save.
    ServletUtils.requireAccess(userService.hasEditAccess(capability.getParentProjectId()));

    log.info("Updating capability: " + capability.getCapabilityId().toString());
    PersistenceManager pm = pmf.getPersistenceManager();
    try {
      Capability oldCapability = pm.getObjectById(Capability.class, capability.getCapabilityId());
      if (oldCapability.getParentProjectId() != capability.getParentProjectId()) {
        log.severe("Possible attack -- capability sent in and capability being overwritten had"
            + " different project IDs.");
        ServletUtils.requireAccess(false);
      }

      pm.makePersistent(capability);
      persistLabels(capability, pm);
    } finally {
      pm.close();
    }
  }

  @Override
  public void removeCapability(Capability capability) {
    if (capability.getCapabilityId() == null) {
      log.info("Attempting to delete unsaved Component. Ignoring.");
      return;
    }

    log.info("Removing Capability: " + capability.getCapabilityId().toString());
    PersistenceManager pm = pmf.getPersistenceManager();
    try {
      Capability capabilityToDelete = pm.getObjectById(
                                          Capability.class, capability.getCapabilityId());
      ServletUtils.requireAccess(userService.hasEditAccess(
          capabilityToDelete.getParentProjectId()));
      pm.deletePersistent(capabilityToDelete);
      deleteLabels(capabilityToDelete, pm);
    } finally {
      pm.close();
    }
  }

  /**
   * Deletes all stored objects of the given type with the field matching the specified ID.
   * Primarily this is used for deleting dependent, child objects when the parent is removed.
   *
   * @param pm the PersistenceManager used to perform the deletion operation.
   * @param type the type of the object to be removed.
   * @param fieldName the name on the object to check.
   * @param fieldValue the value which must match in order for the object to get deleted.
   */
  private <T> void removeObjectsWithFieldValue(
      PersistenceManager pm, Class<T> type, String fieldName, long fieldValue)
      throws IllegalArgumentException {

    // Do a brief sanity check on the field name.
    fieldName = fieldName.trim();
    if ((fieldName.contains(" ")) || (fieldName.contains(";"))) {
      throw new IllegalArgumentException();
    }

    StringBuilder message = new StringBuilder();
    message.append("Deleting all ");
    message.append(type.getCanonicalName());
    message.append(" with '");
    message.append(fieldName);
    message.append("' equal to ");
    message.append(Long.toString(fieldValue));

    log.info(message.toString());

    Query objectsToDeleteQuery = pm.newQuery(type);
    objectsToDeleteQuery.setFilter(fieldName + " == fieldValueParam");
    objectsToDeleteQuery.declareParameters("int fieldValueParam");
    objectsToDeleteQuery.deletePersistentAll(fieldValue);
  }
}
TOP

Related Classes of com.google.testing.testify.risk.frontend.server.service.impl.ProjectServiceImpl

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.