package com.devicehive.dao.rdbms; /* * #%L * DeviceHive Dao RDBMS Implementation * %% * Copyright (C) 2016 DataArt * %% * 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. * #L% */ import com.devicehive.auth.HivePrincipal; import com.devicehive.model.*; import com.devicehive.vo.UserVO; import javax.persistence.criteria.*; import java.util.*; import static com.devicehive.model.Device.Queries.Parameters.GUID; import static java.util.Optional.ofNullable; public class CriteriaHelper { /** * Creates an array of JPA predicates for networks list query. Add filter predicates for name and principal if required. * 1) if name is specified adds 'name = ?' predicate * 2) if name pattern is specified adds 'name like ?' predicate * 3) if principal is user of key without ADMIN role adds predicate for filtering not assigned networks * 4) if principal is key which has permissions only to specific networks adds 'network.id in (allowed_networks)' predicates * * @return array of above predicates * @see {com.devicehive.service.NetworkService#list(String, String, String, boolean, Integer, Integer, HivePrincipal)} */ public static Predicate[] networkListPredicates(CriteriaBuilder cb, Root<Network> from, Optional<String> nameOpt, Optional<String> namePatternOpt, Optional<HivePrincipal> principalOpt) { List<Predicate> predicates = new LinkedList<>(); nameOpt.ifPresent(name -> predicates.add(cb.equal(from.get("name"), name))); namePatternOpt.ifPresent(pattern -> predicates.add(cb.like(from.get("name"), pattern))); principalOpt.flatMap(principal -> { UserVO user = principal.getUser(); return ofNullable(user); }).ifPresent(user -> { if (!user.isAdmin()) { User usr = User.convertToEntity(user); predicates.add(from.join("users").in(usr)); } }); principalOpt.flatMap(principal -> { Set<Long> networks = principal.getNetworkIds(); return ofNullable(networks); }).ifPresent(networks -> { predicates.add(from.<Long>get("id").in(networks)); }); return predicates.toArray(new Predicate[predicates.size()]); } /** * Adds ORDER BY ... ASC/DESC to query * Mutates provided criteria query * @param sortFieldOpt - field to sort by (field name in JPA Entity class) * @param asc - true if order should be ASC, false otherwise */ public static void order(CriteriaBuilder cb, CriteriaQuery<?> cq, Root<?> from, Optional<String> sortFieldOpt, boolean asc) { sortFieldOpt.ifPresent(sortField -> { Order order = asc ? cb.asc(from.get(sortField)) : cb.desc(from.get(sortField)); cq.orderBy(order); }); } public static Predicate[] userListPredicates(CriteriaBuilder cb, Root<User> from, Optional<String> loginOpt, Optional<String> loginPattern, Optional<Integer> roleOpt, Optional<Integer> statusOpt) { List<Predicate> predicates = new LinkedList<>(); if (loginPattern.isPresent()) { loginPattern.ifPresent(pattern -> predicates.add(cb.like(from.get("login"), pattern))); } else { loginOpt.ifPresent(login -> predicates.add(cb.equal(from.get("login"), login))); } roleOpt.ifPresent(role -> predicates.add(cb.equal(from.get("role"), role))); statusOpt.ifPresent(status -> predicates.add(cb.equal(from.get("status"), status))); return predicates.toArray(new Predicate[predicates.size()]); } public static Predicate[] deviceListPredicates(CriteriaBuilder cb, Root<Device> from, List<String> guids, Optional<HivePrincipal> principal) { final List<Predicate> predicates = deviceSpecificPrincipalPredicates(cb, from, principal); if (guids != null && !guids.isEmpty()) { predicates.add(from.get(GUID).in(guids)); } return predicates.toArray(new Predicate[predicates.size()]); } @SuppressWarnings("unchecked") public static Predicate[] deviceListPredicates(CriteriaBuilder cb, Root<Device> from, Optional<String> name, Optional<String> namePattern, Optional<Long> networkId, Optional<String> networkName, Optional<Long> deviceClassId, Optional<String> deviceClassName, Optional<HivePrincipal> principal) { final List<Predicate> predicates = new LinkedList<>(); name.ifPresent(n -> predicates.add(cb.equal(from.<String>get("name"), n))); namePattern.ifPresent(np -> predicates.add(cb.like(from.<String>get("name"), np))); final Join<Device, Network> networkJoin = (Join) from.fetch("network", JoinType.LEFT); networkId.ifPresent(nId -> predicates.add(cb.equal(networkJoin.<Long>get("id"), nId))); networkName.ifPresent(nName -> predicates.add(cb.equal(networkJoin.<String>get("name"), nName))); final Join<Device, DeviceClass> dcJoin = (Join) from.fetch("deviceClass", JoinType.LEFT); deviceClassId.ifPresent(dcId -> predicates.add(cb.equal(dcJoin.<Long>get("id"), dcId))); deviceClassName.ifPresent(dcName -> predicates.add(cb.equal(dcJoin.<String>get("name"), dcName))); predicates.addAll(deviceSpecificPrincipalPredicates(cb, from, principal)); return predicates.toArray(new Predicate[predicates.size()]); } public static Predicate[] deviceClassListPredicates(CriteriaBuilder cb, Root<DeviceClass> from, Optional<String> name, Optional<String> namePattern) { final List<Predicate> predicates = new LinkedList<>(); if (namePattern.isPresent()) { namePattern.ifPresent(np -> predicates.add(cb.like(from.get("name"), np))); } else { name.ifPresent(n -> predicates.add(cb.equal(from.get("name"), n))); } return predicates.toArray(new Predicate[predicates.size()]); } @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); from.fetch("deviceClass", JoinType.LEFT); //need this fetch to populate deviceClass principal.ifPresent(p -> { UserVO user = p.getUser(); if (user != null && !user.isAdmin()) { // Joining after check to prevent duplicate objects final Join<Device, Network> usersJoin = (Join) networkJoin.fetch("users", JoinType.LEFT); predicates.add(cb.equal(usersJoin.<Long>get("id"), user.getId())); } if (p.getNetworkIds() != null) { predicates.add(networkJoin.<Long>get("id").in(p.getNetworkIds())); } if (p.getDeviceGuids() != null) { predicates.add(from.<String>get("guid").in(p.getDeviceGuids())); } }); return predicates; } }