@Transactional(propagation = Propagation.SUPPORTS)
  public boolean hasAccessToDevice(AccessKey accessKey, String deviceGuid) {
    Set<AccessKeyPermission> permissions = accessKey.getPermissions();
    Set<String> allowedDevices = new HashSet<>();
    Set<Long> allowedNetworks = new HashSet<>();

    User accessKeyUser = userService.findUserWithNetworks(accessKey.getUser().getId());
    Set<AccessKeyPermission> toRemove = new HashSet<>();

    Device device =
        genericDAO
            .createNamedQuery(Device.class, "Device.findByUUID", of(CacheConfig.refresh()))
            .setParameter("guid", deviceGuid)
            .getSingleResult();

    for (AccessKeyPermission currentPermission : permissions) {
      if (currentPermission.getDeviceGuidsAsSet() == null) {
        allowedDevices.add(null);
      } else {
        if (!currentPermission.getDeviceGuidsAsSet().contains(deviceGuid)) {
          toRemove.add(currentPermission);
        } else {
          allowedDevices.addAll(currentPermission.getDeviceGuidsAsSet());
        }
      }
      if (currentPermission.getNetworkIdsAsSet() == null) {
        allowedNetworks.add(null);
      } else {
        if (device.getNetwork() != null) {
          if (!currentPermission.getNetworkIdsAsSet().contains(device.getNetwork().getId())) {
            toRemove.add(currentPermission);
          } else {
            allowedNetworks.addAll(currentPermission.getNetworkIdsAsSet());
          }
        }
      }
    }
    permissions.removeAll(toRemove);
    boolean hasAccess;
    hasAccess =
        allowedDevices.contains(null)
            ? userService.hasAccessToDevice(accessKeyUser, device.getGuid())
            : allowedDevices.contains(device.getGuid())
                && userService.hasAccessToDevice(accessKeyUser, device.getGuid());

    hasAccess =
        hasAccess && allowedNetworks.contains(null)
            ? accessKeyUser.isAdmin() || accessKeyUser.getNetworks().contains(device.getNetwork())
            : (accessKeyUser.isAdmin() || accessKeyUser.getNetworks().contains(device.getNetwork()))
                && allowedNetworks.contains(device.getNetwork().getId());

    return hasAccess;
  }
 @Transactional(propagation = Propagation.SUPPORTS)
 public boolean hasAccessToNetwork(AccessKey accessKey, Network targetNetwork) {
   Set<AccessKeyPermission> permissions = accessKey.getPermissions();
   User user = accessKey.getUser();
   boolean hasNullPermission =
       permissions.stream().anyMatch(perm -> perm.getNetworkIdsAsSet() == null);
   if (hasNullPermission) {
     return userService.hasAccessToNetwork(user, targetNetwork);
   } else {
     Set<Long> allowedNetworks =
         permissions
             .stream()
             .map(AccessKeyPermission::getNetworkIdsAsSet)
             .flatMap(Collection::stream)
             .collect(Collectors.toSet());
     user = userService.findUserWithNetworks(user.getId());
     return allowedNetworks.contains(targetNetwork.getId())
         && (user.isAdmin() || user.getNetworks().contains(targetNetwork));
   }
 }
  @SuppressWarnings("unchecked")
  private static List<Predicate> deviceSpecificPrincipalPredicates(
      CriteriaBuilder cb, Root<Device> from, Optional<HivePrincipal> principal) {
    final List<Predicate> predicates = new LinkedList<>();
    final Join<Device, Network> networkJoin = (Join) from.fetch("network", JoinType.LEFT);
    final Join<Device, Network> usersJoin = (Join) networkJoin.fetch("users", JoinType.LEFT);
    from.fetch("deviceClass", JoinType.LEFT); // need this fetch to populate deviceClass
    principal.ifPresent(
        p -> {
          User user = p.getUser();
          if (user == null && p.getKey() != null) {
            user = p.getKey().getUser();
          }
          if (user != null && !user.isAdmin()) {
            predicates.add(cb.equal(usersJoin.<Long>get("id"), user.getId()));
          }

          if (p.getDevice() != null) {
            predicates.add(cb.equal(from.<Long>get("id"), p.getDevice().getId()));
          }

          if (p.getKey() != null) {
            for (AccessKeyBasedFilterForDevices extraFilter :
                AccessKeyBasedFilterForDevices.createExtraFilters(p.getKey().getPermissions())) {
              if (extraFilter.getDeviceGuids() != null) {
                predicates.add(from.<String>get("guid").in(extraFilter.getDeviceGuids()));
              }
              if (extraFilter.getNetworkIds() != null) {
                predicates.add(networkJoin.<Long>get("id").in(extraFilter.getNetworkIds()));
              }
            }
          }
        });

    return predicates;
  }
  public static Predicate[] oAuthGrantsListPredicates(
      CriteriaBuilder cb,
      Root<OAuthGrant> from,
      User user,
      Optional<Date> startOpt,
      Optional<Date> endOpt,
      Optional<String> oAuthIdOpt,
      Optional<Integer> typeOpt,
      Optional<String> scopeOpt,
      Optional<String> redirectUri,
      Optional<Integer> accessType) {
    List<Predicate> predicates = new LinkedList<>();

    if (!user.isAdmin()) {
      predicates.add(from.join("user").in(user));
    }

    startOpt.ifPresent(start -> predicates.add(cb.greaterThan(from.get("timestamp"), start)));
    endOpt.ifPresent(end -> predicates.add(cb.lessThan(from.get("timestamp"), end)));
    oAuthIdOpt.ifPresent(id -> predicates.add(cb.equal(from.join("client").get("oauthId"), id)));
    typeOpt.ifPresent(type -> predicates.add(cb.equal(from.get("type"), type)));
    scopeOpt.ifPresent(scope -> predicates.add(cb.equal(from.get("scope"), scope)));
    redirectUri.ifPresent(uri -> predicates.add(cb.equal(from.get("redirectUri"), uri)));
    accessType.ifPresent(at -> predicates.add(cb.equal(from.get("accessType"), at)));

    return predicates.toArray(new Predicate[predicates.size()]);
  }