package com.devicehive.dao.riak; /* * #%L * DeviceHive Dao Riak 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.basho.riak.client.api.commands.indexes.BinIndexQuery; import com.basho.riak.client.api.commands.kv.DeleteValue; import com.basho.riak.client.api.commands.kv.FetchValue; import com.basho.riak.client.api.commands.kv.StoreValue; import com.basho.riak.client.api.commands.mapreduce.BucketMapReduce; import com.basho.riak.client.api.commands.mapreduce.MapReduce; import com.basho.riak.client.core.query.Location; import com.basho.riak.client.core.query.Namespace; import com.devicehive.auth.HivePrincipal; import com.devicehive.dao.DeviceDao; import com.devicehive.dao.NetworkDao; import com.devicehive.dao.UserDao; import com.devicehive.dao.riak.model.RiakNetwork; import com.devicehive.dao.riak.model.UserNetwork; import com.devicehive.exceptions.HivePersistenceLayerException; import com.devicehive.vo.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import javax.validation.constraints.NotNull; import java.util.*; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import java.util.stream.Stream; @Repository public class NetworkDaoRiakImpl extends RiakGenericDao implements NetworkDao { private static final Namespace NETWORK_NS = new Namespace("network"); private static final Location COUNTERS_LOCATION = new Location(new Namespace("counters", "dh_counters"), "networkCounter"); @Autowired private UserNetworkDaoRiakImpl userNetworkDao; @Autowired private NetworkDeviceDaoRiakImpl networkDeviceDao; private DeviceDao deviceDao; private UserDao userDao; public NetworkDaoRiakImpl() { } void setUserDao(UserDao userDao) { this.userDao = userDao; } void setDeviceDao(DeviceDao deviceDao) { this.deviceDao = deviceDao; } @Override public List<NetworkVO> findByName(String name) { if (name == null) { return Collections.emptyList(); } BinIndexQuery biq = new BinIndexQuery.Builder(NETWORK_NS, "name", name).build(); try { BinIndexQuery.Response response = client.execute(biq); List<RiakNetwork> result = fetchMultiple(response, RiakNetwork.class); return result.stream().map(RiakNetwork::convert).collect(Collectors.toList()); } catch (ExecutionException | InterruptedException e) { throw new HivePersistenceLayerException("Can't find networks by name", e); } } @Override public void persist(@NotNull NetworkVO newNetwork) { if (newNetwork.getId() == null) { newNetwork.setId(getId(COUNTERS_LOCATION)); } RiakNetwork network = RiakNetwork.convert(newNetwork); Location location = new Location(NETWORK_NS, String.valueOf(network.getId())); StoreValue storeOp = new StoreValue.Builder(network) .withLocation(location) .withOption(quorum.getWriteQuorumOption(), quorum.getWriteQuorum()) .build(); try { client.execute(storeOp); } catch (ExecutionException | InterruptedException e) { throw new HivePersistenceLayerException("Can't execute store operation on network network", e); } } @Override public List<NetworkWithUsersAndDevicesVO> getNetworksByIdsAndUsers(Long idForFiltering, Set<Long> networkdIds, Set<Long> permittedNetworks) { Set<Long> intersection = networkdIds; if (permittedNetworks != null) { intersection = networkdIds.stream() .filter(permittedNetworks::contains) .collect(Collectors.toSet()); } Stream<NetworkWithUsersAndDevicesVO> networkStream = intersection.stream() .map(this::findWithUsersAndDevices) .filter(Optional::isPresent) .map(Optional::get); if (idForFiltering != null) { networkStream = networkStream.filter(n -> n.getUsers().stream().anyMatch(u -> u.getId().equals(idForFiltering))); } return networkStream.collect(Collectors.toList()); } @Override public int deleteById(long id) { Location location = new Location(NETWORK_NS, String.valueOf(id)); DeleteValue deleteOp = new DeleteValue.Builder(location).build(); try { client.execute(deleteOp); return 1; } catch (ExecutionException | InterruptedException e) { return 0; } } @Override public NetworkVO find(@NotNull Long networkId) { RiakNetwork vo = get(networkId); return RiakNetwork.convert(vo); } private RiakNetwork get(@NotNull Long networkId) { Location location = new Location(NETWORK_NS, String.valueOf(networkId)); FetchValue fetchOp = new FetchValue.Builder(location) .withOption(quorum.getReadQuorumOption(), quorum.getReadQuorum()) .build(); try { return getOrNull(client.execute(fetchOp), RiakNetwork.class); } catch (ExecutionException | InterruptedException e) { throw new HivePersistenceLayerException("Can't fetch network by id", e); } } @Override public NetworkVO merge(@NotNull NetworkVO network) { assert network.getId() != null; RiakNetwork existing = get(network.getId()); existing.setKey(network.getKey()); existing.setName(network.getName()); existing.setDescription(network.getDescription()); Location location = new Location(NETWORK_NS, String.valueOf(network.getId())); StoreValue storeOp = new StoreValue.Builder(existing) .withLocation(location) .withOption(quorum.getWriteQuorumOption(), quorum.getWriteQuorum()) .build(); try { client.execute(storeOp); return RiakNetwork.convert(existing); } catch (ExecutionException | InterruptedException e) { throw new HivePersistenceLayerException("Can't execute store operation on network network", e); } } @Override public void assignToNetwork(NetworkVO network, UserVO user) { assert network != null && network.getId() != null; assert user != null && user.getId() != null; Set<Long> networksForUser = userNetworkDao.findNetworksForUser(user.getId()); if (!networksForUser.contains(network.getId())) { userNetworkDao.persist(new UserNetwork(user.getId(), network.getId())); } } @Override public List<NetworkVO> list(String name, String namePattern, String sortField, boolean isSortOrderAsc, Integer take, Integer skip, Optional<HivePrincipal> principalOptional) { BucketMapReduce.Builder builder = new BucketMapReduce.Builder() .withNamespace(NETWORK_NS); addMapValues(builder); if (name != null) { addReduceFilter(builder, "name", FilterOperator.EQUAL, name); } else if (namePattern != null) { namePattern = namePattern.replace("%", ""); addReduceFilter(builder, "name", FilterOperator.REGEX, namePattern); } if (principalOptional.isPresent()) { HivePrincipal principal = principalOptional.get(); if (principal != null) { UserVO user = principal.getUser(); if (user != null && !user.isAdmin()) { Set<Long> networks = userNetworkDao.findNetworksForUser(user.getId()); addReduceFilter(builder, "id", FilterOperator.IN, networks); } if (principal.getNetworkIds() != null) { Set<Long> ids = principal.getNetworkIds(); if (!ids.isEmpty()) { addReduceFilter(builder, "id", FilterOperator.IN, ids); } } } } addReduceSort(builder, sortField, isSortOrderAsc); addReducePaging(builder, true, take, skip); try { MapReduce.Response response = client.execute(builder.build()); return response.getResultsFromAllPhases(RiakNetwork.class).stream() .map(RiakNetwork::convert).collect(Collectors.toList()); } catch (InterruptedException | ExecutionException e) { throw new HivePersistenceLayerException("Cannot get list of networks.", e); } } @Override public Optional<NetworkVO> findFirstByName(String name) { return findByName(name).stream().findFirst(); } private Optional<NetworkWithUsersAndDevicesVO> findWithUsersAndDevices(long networkId) { Optional<NetworkWithUsersAndDevicesVO> result = findWithUsers(networkId); if (result.isPresent()) { Set<DeviceVO> devices = networkDeviceDao.findDevicesForNetwork(networkId).stream() .map(deviceDao::findByUUID) .collect(Collectors.toSet()); result.get().setDevices(devices); return result; } else { return Optional.empty(); } } @Override public Optional<NetworkWithUsersAndDevicesVO> findWithUsers(long networkId) { NetworkVO networkVO = find(networkId); if (networkVO != null) { NetworkWithUsersAndDevicesVO vo = new NetworkWithUsersAndDevicesVO(networkVO); Set<UserVO> users = userNetworkDao.findUsersInNetwork(networkId).stream() .map(userDao::find) .collect(Collectors.toSet()); vo.setUsers(users); return Optional.of(vo); } else { return Optional.empty(); } } }