class JpaSortBuilder {

  public List<Order> buildSortOrders(SortRequest sortRequest,
      JpaPredicateVisitor<T> visitor) {

    if (null == sortRequest || null == sortRequest.getProperties()) {
      return Collections.emptyList();
    }

    CriteriaBuilder builder = visitor.getCriteriaBuilder();
    List<SortRequestProperty> sortProperties = sortRequest.getProperties();
    List<Order> sortOrders = new ArrayList<>(sortProperties.size());

    for (SortRequestProperty sort : sortProperties) {
      String propertyId = sort.getPropertyId();

      List<? extends SingularAttribute<?, ?>> singularAttributes = visitor.getPredicateMapping(propertyId);

      if (null == singularAttributes || singularAttributes.size() == 0) {
        continue;
      }

      Path<?> path = null;
      for (SingularAttribute<?, ?> singularAttribute : singularAttributes) {
        if (null == path) {

          CriteriaQuery<T> query = visitor.getCriteriaQuery();
          Set<Root<?>> roots = query.getRoots();

          // if there are existing roots; use the existing roots to prevent more
          // roots from being added potentially causing a cartesian product
          // where we don't want one
          if (null != roots && !roots.isEmpty()) {
            Iterator<Root<?>> iterator = roots.iterator();
            while (iterator.hasNext()) {
              Root<?> root = iterator.next();

              Class<?> visitorEntityClass = visitor.getEntityClass();
              if (ObjectUtils.equals(visitorEntityClass, root.getJavaType())
                  || ObjectUtils.equals(visitorEntityClass, root.getModel().getJavaType())) {
                path = root.get(singularAttribute.getName());
                break;
              }
            }
          }

          // no roots exist already which match this entity class, create a new
          // path
          if (null == path) {
            path = query.from(visitor.getEntityClass()).get(singularAttribute.getName());
          }
        } else {
          path = path.get(singularAttribute.getName());
        }
      }

      Order sortOrder = null;
      if (sort.getOrder() == org.apache.ambari.server.controller.spi.SortRequest.Order.ASC) {
        sortOrder = builder.asc(path);
      } else {
        sortOrder = builder.desc(path);
      }

      sortOrders.add(sortOrder);
    }

    return sortOrders;
  }

  public  JpaSortBuilder();

}