package com.aemreunal.service; /* * *********************** * * Copyright (c) 2015 * * * * This code belongs to: * * * * @author Ahmet Emre Ünal * * S001974 * * * * aemreunal@gmail.com * * emre.unal@ozu.edu.tr * * * * aemreunal.com * * *********************** * */ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import javax.validation.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import com.aemreunal.config.GlobalSettings; import com.aemreunal.domain.Beacon; import com.aemreunal.domain.Connection; import com.aemreunal.domain.Region; import com.aemreunal.domain.Scenario; import com.aemreunal.exception.MalformedRequestException; import com.aemreunal.exception.beacon.BeaconAlreadyExistsException; import com.aemreunal.exception.beacon.BeaconNotFoundException; import com.aemreunal.exception.connection.ConnectionNotPossibleException; import com.aemreunal.exception.project.ProjectNotFoundException; import com.aemreunal.exception.region.RegionNotFoundException; import com.aemreunal.exception.textStorage.TextDeleteException; import com.aemreunal.exception.textStorage.TextSaveException; import com.aemreunal.helper.TextStorage; import com.aemreunal.repository.beacon.BeaconRepo; import com.aemreunal.repository.beacon.BeaconSpecs; @Transactional @Service public class BeaconService { @Autowired private RegionService regionService; @Autowired private BeaconRepo beaconRepo; @Autowired private TextStorage textStorage; @Autowired private BCryptPasswordEncoder passwordEncoder; public Beacon saveNewBeacon(String username, Long projectId, Long regionId, Beacon beacon, MultipartFile locationInfoText) throws TextSaveException { beacon = this.save(username, projectId, regionId, beacon); if (locationInfoText != null) { beacon = setLocationInfoText(username, projectId, regionId, beacon, locationInfoText); } return beacon; } private Beacon setLocationInfoText(String username, Long projectId, Long regionId, Beacon beacon, MultipartFile locationInfoText) throws TextSaveException { GlobalSettings.log("Setting location info text of beacon with ID = \'" + beacon.getBeaconId() + "\'"); String textFileName = textStorage.saveText(projectId, regionId, beacon.getBeaconId(), locationInfoText); beacon.setLocationInfoTextFileName(textFileName); return this.save(username, projectId, regionId, beacon); } /** * Saves/updates the given beacon * * @param beacon * The beacon to save/update * * @return The saved/updated beacon */ private Beacon save(String username, Long projectId, Long regionId, Beacon beacon) throws ConstraintViolationException, BeaconAlreadyExistsException, MalformedRequestException { GlobalSettings.log("Saving beacon with ID = \'" + beacon.getBeaconId() + "\'"); Region region = regionService.getRegion(username, projectId, regionId); if (beacon.getRegion() == null) { // This means it hasn't been created yet validateBeacon(username, projectId, regionId, beacon, region); beacon.setRegion(region); } return beaconRepo.save(beacon); } private void validateBeacon(String username, Long projectId, Long regionId, Beacon beacon, Region region) throws BeaconAlreadyExistsException, MalformedRequestException { if (beaconExists(username, projectId, regionId, beacon)) { // First, verify the beacon doesn't already exist throw new BeaconAlreadyExistsException(beacon); } else if (!region.beaconCoordsAreValid(beacon)) { // Check whether the beacon coordinates are valid throw new MalformedRequestException(); } } private boolean beaconExists(String username, Long projectId, Long regionId, Beacon beacon) { Set<Beacon> beacons; try { beacons = findBeaconsBySpecs(username, projectId, regionId, beacon.getUuid(), beacon.getMajor(), beacon.getMinor(), null); return beacons.size() != 0; } catch (BeaconNotFoundException e) { GlobalSettings.err("No such beacon has been found. Will return false;"); } return false; } /** * Finds beacons conforming to given specifications * * @param username * The username constraint * @param projectId * The project ID constraint * @param regionId * The region ID constraint * @param uuid * The UUID field constraint * @param major * The Major field constraint * @param minor * The Minor field constraint * @param designated * The designated field constraint * * @return The list of beacons conforming to given constraints */ @Transactional(readOnly = true) public LinkedHashSet<Beacon> findBeaconsBySpecs(String username, Long projectId, Long regionId, String uuid, Integer major, Integer minor, Boolean designated) throws BeaconNotFoundException { GlobalSettings.log("Finding beacons with UUID = \'" + uuid + "\' major = \'" + major + "\' minor = \'" + minor + "\' designated = \'" + designated + "\'"); List<Beacon> beacons = beaconRepo.findAll(BeaconSpecs.beaconWithSpecification(username, projectId, regionId, uuid, major, minor, designated)); // if (beacons.size() == 0) { // throw new BeaconNotFoundException(); // } return beacons.stream() .sorted() .collect(Collectors.toCollection(LinkedHashSet::new)); } @Transactional(readOnly = true) public Beacon queryForBeacon(String uuid, Integer major, Integer minor, String projectSecret) throws BeaconNotFoundException { List<Beacon> beacons = beaconRepo.findAll(BeaconSpecs.beaconWithSpecification(null, null, null, uuid, major, minor, null)); for (Beacon beacon : beacons) { if (passwordEncoder.matches(projectSecret, beacon.getRegion().getProject().getProjectSecret())) { return beacon; } } throw new BeaconNotFoundException(); } /** * Finds the {@link com.aemreunal.domain.Beacon beacon} with the specified beaconId in * a {@link com.aemreunal.domain.Region region}. * * @param username * The username of the {@link com.aemreunal.domain.User owner} of the project * @param projectId * The ID of the project * @param regionId * The ID of the region * @param beaconId * The ID of the beacon to find * * @return The beacon * * @throws com.aemreunal.exception.beacon.BeaconNotFoundException * If the specified beacon does not exist. * @throws com.aemreunal.exception.project.ProjectNotFoundException * If the specified project does not exist. * @throws com.aemreunal.exception.region.RegionNotFoundException * If the specified region does not exist. */ @Transactional(readOnly = true) public Beacon getBeacon(String username, Long projectId, Long regionId, Long beaconId) throws BeaconNotFoundException, ProjectNotFoundException, RegionNotFoundException { GlobalSettings.log("Finding beacon with ID = \'" + beaconId + "\' in project = \'" + projectId + "\' and in region = \'" + regionId + "\'"); Region region = regionService.getRegion(username, projectId, regionId); Beacon beacon = beaconRepo.findByBeaconIdAndRegion(beaconId, region); if (beacon == null) { throw new BeaconNotFoundException(beaconId); } return beacon; } /** * Returns the list of {@link com.aemreunal.domain.Beacon beacons} that belong to a * {@link com.aemreunal.domain.Region region}. * * @param username * The username of the {@link com.aemreunal.domain.User owner} of the * project. * @param projectId * The ID of the project. * @param regionId * The ID of the region. * * @return The list of beacons that belong to a region. Returns an empty list if the * region has no beacons. */ @Transactional(readOnly = true) public LinkedHashSet<Beacon> getBeaconsOfRegion(String username, Long projectId, Long regionId) { return regionService.getMembersOfRegion(username, projectId, regionId); } @Transactional(readOnly = true) public Set<Beacon> getDesignatedBeaconsOfRegion(String username, Long projectId, Long regionId) { return this.findBeaconsBySpecs(username, projectId, regionId, null, null, null, Boolean.TRUE); } public Beacon addConnection(String username, Long projectId, Long regionId, Long beaconId, Connection connection) throws ConnectionNotPossibleException { Beacon beacon = this.getBeacon(username, projectId, regionId, beaconId); if (!beacon.isDesignated()) { throw new ConnectionNotPossibleException(beaconId); } beacon.addConnection(connection); regionService.markRegionAsUpdated(username, projectId, regionId); return this.save(username, projectId, regionId, beacon); } public Beacon removeConnection(String username, Long projectId, Long regionId, Long beaconId, Connection connection) { Beacon beacon = this.getBeacon(username, projectId, regionId, beaconId); beacon.removeConnection(connection); regionService.markRegionAsUpdated(username, projectId, regionId); return this.save(username, projectId, regionId, beacon); } @Transactional(readOnly = true) public Set<Connection> getConnectionsOfBeacon(String username, Long projectId, Long regionId, Long beaconId) { Beacon beacon = this.getBeacon(username, projectId, regionId, beaconId); return beacon.getConnections(); } public void setBeaconScenario(String username, Long projectId, Long regionId, Beacon beacon, Scenario scenario) { beacon.setScenario(scenario); save(username, projectId, regionId, beacon); } public Beacon delete(String username, Long projectId, Long regionId, Long beaconId) { GlobalSettings.log("Deleting beacon with ID = \'" + beaconId + "\'"); // Retrieving beacon to ensure that beacon exists and is part of this user/project/region etc. Beacon beacon = getBeacon(username, projectId, regionId, beaconId); deleteLocationTextFile(projectId, regionId, beaconId, beacon.getLocationInfoTextFileName()); beaconRepo.delete(beacon); return beacon; } private void deleteLocationTextFile(Long projectId, Long regionId, Long beaconId, String locationInfoTextFileName) { try { textStorage.deleteText(projectId, regionId, beaconId, locationInfoTextFileName); } catch (TextDeleteException e) { GlobalSettings.err("WARNING: Location info text file for project: " + projectId + ", region " + regionId + ", beacon " + beaconId + ", file name: " + locationInfoTextFileName + " could not be deleted! " + "May need to be deleted manually!"); } } }