edu.zipcloud.cloudstreetmarket.core.services.CommunityServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for edu.zipcloud.cloudstreetmarket.core.services.CommunityServiceImpl.java

Source

/***
 *  Cloudstreetmarket.com is a Spring MVC showcase application developed 
 *  with the book Spring MVC Cookbook [PACKT] (2015). 
 *    Copyright (C) 2015  Alex Bretet
 *  
 *  This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 **/
package edu.zipcloud.cloudstreetmarket.core.services;

import static edu.zipcloud.cloudstreetmarket.core.enums.Role.*;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Nullable;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.ResourceAccessException;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import edu.zipcloud.cloudstreetmarket.core.daos.ActionRepository;
import edu.zipcloud.cloudstreetmarket.core.daos.UserRepository;
import edu.zipcloud.cloudstreetmarket.core.dtos.UserActivityDTO;
import edu.zipcloud.cloudstreetmarket.core.dtos.UserDTO;
import edu.zipcloud.cloudstreetmarket.core.entities.AccountActivity;
import edu.zipcloud.cloudstreetmarket.core.entities.Action;
import edu.zipcloud.cloudstreetmarket.core.entities.Authority;
import edu.zipcloud.cloudstreetmarket.core.entities.CurrencyExchange;
import edu.zipcloud.cloudstreetmarket.core.entities.StockQuote;
import edu.zipcloud.cloudstreetmarket.core.entities.Transaction;
import edu.zipcloud.cloudstreetmarket.core.entities.User;
import edu.zipcloud.cloudstreetmarket.core.enums.Role;
import edu.zipcloud.cloudstreetmarket.core.enums.SupportedLanguage;
import edu.zipcloud.cloudstreetmarket.core.enums.UserActivityType;
import edu.zipcloud.cloudstreetmarket.core.helpers.CommunityServiceHelper;
import edu.zipcloud.cloudstreetmarket.core.util.AuthenticationUtil;
import edu.zipcloud.cloudstreetmarket.core.util.TransactionUtil;

@Service(value = "communityServiceImpl")
@Transactional(propagation = Propagation.REQUIRED)
@PropertySource(value = "file:${user.home}/app/cloudstreetmarket.properties")
public class CommunityServiceImpl implements CommunityService {

    @Autowired
    private ActionRepository actionRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private CommunityServiceHelper communityServiceHelper;

    public static final Class<?>[] PUBLIC_ACTIVITY_TYPES = { AccountActivity.class, Transaction.class };

    private String[] reservedUserNames = { "leaderboard" };

    @Override
    public Page<UserActivityDTO> getPublicActivity(Pageable pageable) {
        Page<Action> actions = actionRepository.findAll(pageable);
        List<UserActivityDTO> result = transform(actions);
        return new PageImpl<>(result, pageable, actions.getTotalElements());
    }

    private List<UserActivityDTO> transform(Iterable<Action> actions) {
        List<UserActivityDTO> result = Lists.newLinkedList();
        actions.forEach(a -> {
            if (a instanceof AccountActivity) {
                UserActivityDTO accountActivity = new UserActivityDTO(a.getUser().getUsername(),
                        a.getUser().getProfileImg(), ((AccountActivity) a).getType(),
                        ((AccountActivity) a).getDate(), a.getId());
                accountActivity.setSocialReport(a.getSocialEventAction());
                result.add(accountActivity);
            } else if (a instanceof Transaction) {
                UserActivityDTO transaction = new UserActivityDTO((Transaction) a);
                transaction.setSocialReport(a.getSocialEventAction());
                result.add(transaction);
            }
        });
        return result;
    }

    @Override
    public User findByUserName(String userName) {
        return userRepository.findOne(userName);
    }

    @Override
    public User createUser(User user, Role role) {
        if (findByUserName(user.getUsername()) != null
                || Arrays.asList(reservedUserNames).contains(user.getUsername())) {
            throw new ConstraintViolationException("The provided user name already exists!", null, null);
        }
        user.addAuthority(new Authority(user, role));
        user.addAction(new AccountActivity(user, UserActivityType.REGISTER, new Date()));
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        return userRepository.save(user);
    }

    @Override
    public User createUser(User user, Role[] roles) {
        if (findByUserName(user.getUsername()) != null
                || Arrays.asList(reservedUserNames).contains(user.getUsername())) {
            throw new ConstraintViolationException("The provided user name already exists!", null, null);
        }

        Arrays.asList(roles).forEach(r -> {
            user.addAuthority(new Authority(user, r));
        });
        user.addAction(new AccountActivity(user, UserActivityType.REGISTER, new Date()));
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        return userRepository.save(user);
    }

    @Override
    public User updateUser(User user) {
        Preconditions.checkNotNull(user);
        if (AuthenticationUtil.isThePrincipal(user.getId()) || AuthenticationUtil.userHasRole(ROLE_ADMIN)) {
            user.setPassword(passwordEncoder.encode(user.getPassword()));
            return userRepository.save(user);
        } else {
            throw new BadCredentialsException("You are not authorized to perfom this operation!");
        }
    }

    public User createUserWithBalance(User user, Role[] roles, BigDecimal balance) {
        user.setBalance(balance);
        user.setLanguage(SupportedLanguage.EN);
        return createUser(user, roles);
    }

    @Override
    public Page<UserDTO> search(Specification<User> spec, Pageable pageable) {
        Page<User> users = userRepository.findAll(spec, pageable);
        List<UserDTO> result = users.getContent().stream().map(u -> hideSensitiveFieldsIfNecessary(new UserDTO(u)))
                .collect(Collectors.toCollection(LinkedList::new));
        return new PageImpl<>(result, pageable, users.getTotalElements());
    }

    @Override
    public User findOne(String username) {
        return userRepository.findOne(username);
    }

    @Override
    @Secured({ ADMIN, SYSTEM })
    public void delete(String userName) {
        userRepository.delete(userName);
    }

    @Override
    @Secured(ADMIN)
    public Page<User> findAll(Pageable pageable) {
        return userRepository.findAll(pageable);
    }

    @Override
    public Page<UserDTO> getLeaders(Pageable pageable) {
        Page<User> users = userRepository.findAll(pageable);
        List<UserDTO> result = users.getContent().stream().map(u -> hideSensitiveInformation(new UserDTO(u)))
                .collect(Collectors.toCollection(LinkedList::new));
        return new PageImpl<>(result, pageable, users.getTotalElements());
    }

    @Override
    public UserDTO getUser(String username) {
        User user = userRepository.findOne(username);
        if (user == null) {
            throw new ResourceNotFoundException();
        }
        UserDTO userDTO = new UserDTO(user);
        return hideSensitiveFieldsIfNecessary(userDTO);
    }

    private static UserDTO hideSensitiveInformation(final UserDTO userDTO) {
        userDTO.setPassword("hidden");
        userDTO.setEmail("hidden");
        return userDTO;
    }

    private UserDTO hideSensitiveFieldsIfNecessary(UserDTO userDTO) {
        Preconditions.checkNotNull(userDTO);
        if (AuthenticationUtil.isThePrincipal(userDTO.getId())) {
            return userDTO;
        } else {
            return hideSensitiveInformation(userDTO);
        }
    }

    @Override
    public User identifyUser(User user) {
        Preconditions.checkArgument(user.getPassword() != null, "The provided password cannot be null!");
        Preconditions.checkArgument(StringUtils.isNotEmpty(user.getPassword()),
                "The provided password cannot be empty!");

        User retreivedUser = userRepository.findOne(user.getUsername());
        if (!passwordEncoder.matches(user.getPassword(), retreivedUser.getPassword())) {
            throw new BadCredentialsException("No match has been found with the provided credentials!");
        }
        return retreivedUser;
    }

    @Override
    @Secured({ ADMIN, SYSTEM })
    public User getUserByEmail(String email) {
        Set<User> result = userRepository.findByEmail(email);
        return result != null ? result.stream().findFirst().orElse(null) : null;
    }

    @Override
    public Set<Authority> createAuthorities(Role[] roles) {
        Set<Authority> authorities = Sets.newHashSet();
        Arrays.asList(roles).forEach(r -> authorities.add(new Authority(r.name())));
        return authorities;
    }

    @Override
    public void save(User user) {
        userRepository.save(user);
    }

    @Override
    public UserDTO findByLogin(String login) {
        User user = userRepository.findOne(login);
        if (user == null) {
            throw new ResourceNotFoundException();
        }
        UserDTO userDTO = new UserDTO(user);
        return hideSensitiveFieldsIfNecessary(userDTO);
    }

    @Override
    public void registerUser(User user) {
        String password = user.getPassword();
        if (password == null) {
            password = communityServiceHelper.generatePassword();
        }
        user.setPassword(passwordEncoder.encode(password));
        userRepository.save(user);
    }

    @Override
    public Authentication signInUser(User user) {
        Authentication authentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(),
                user.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        return authentication;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User user = userRepository.findOne(username);
        Authentication auth;

        if (user != null) {
            return user;
        }

        SecurityContext securityContext = SecurityContextHolder.getContext();
        if (securityContext != null) {
            auth = securityContext.getAuthentication();
            if (auth != null) {
                Object principal = auth.getPrincipal();
                if (principal instanceof User) {
                    return (User) principal;
                }
            }
        }

        //fallback
        throw new ResourceAccessException("No found user for username: " + username);
    }

    @Override
    public boolean isAffordableToUser(int quantity, StockQuote quote, User user,
            @Nullable CurrencyExchange currencyExchange) {
        BigDecimal priceInUserCurrency = TransactionUtil.getPriceInUserCurrency(quote, UserActivityType.BUY,
                quantity, user, currencyExchange);
        return user.getBalance().compareTo(priceInUserCurrency) >= 0;
    }

    @Override
    public void alterUserBalance(int quantity, StockQuote quote, User user, UserActivityType type,
            @Nullable CurrencyExchange currencyExchange) {
        BigDecimal priceInUserCurrency = TransactionUtil.getPriceInUserCurrency(quote, type, quantity, user,
                currencyExchange);

        if (UserActivityType.BUY.equals(type)) {
            user.setBalance(user.getBalance().add(priceInUserCurrency.negate()));
        } else if (UserActivityType.SELL.equals(type)) {
            user.setBalance(user.getBalance().add(priceInUserCurrency));
        }

        userRepository.save(user);
    }

    @Override
    public User hydrate(User user) {
        //TODO
        return user;
    }
}