package com.ciandt.techgallery.service.impl;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.lang.StringUtils;
import com.ciandt.techgallery.persistence.dao.StorageDAO;
import com.ciandt.techgallery.persistence.dao.TechnologyDAO;
import com.ciandt.techgallery.persistence.dao.impl.TechnologyDAOImpl;
import com.ciandt.techgallery.persistence.dao.storage.StorageDAOImpl;
import com.ciandt.techgallery.persistence.model.TechGalleryUser;
import com.ciandt.techgallery.persistence.model.Technology;
import com.ciandt.techgallery.service.TechnologyService;
import com.ciandt.techgallery.service.UserServiceTG;
import com.ciandt.techgallery.service.enums.RecommendationEnums;
import com.ciandt.techgallery.service.enums.TechnologyOrderOptionEnum;
import com.ciandt.techgallery.service.enums.ValidationMessageEnums;
import com.ciandt.techgallery.service.model.Response;
import com.ciandt.techgallery.service.model.TechnologiesResponse;
import com.ciandt.techgallery.service.model.TechnologyFilter;
import com.google.api.server.spi.response.BadRequestException;
import com.google.api.server.spi.response.InternalServerErrorException;
import com.google.api.server.spi.response.NotFoundException;
import com.google.appengine.api.oauth.OAuthRequestException;
import com.google.appengine.api.users.User;
/**
* Services for Technology Endpoint requests.
*
* @author felipers
*
*/
public class TechnologyServiceImpl implements TechnologyService {
/*
* Attributes --------------------------------------------
*/
private static TechnologyServiceImpl instance;
/** tech gallery user service. */
UserServiceTG userService = UserServiceTGImpl.getInstance();
TechnologyDAO technologyDAO = TechnologyDAOImpl.getInstance();
StorageDAO storageDAO = StorageDAOImpl.getInstance();
/*
* Constructors --------------------------------------------
*/
private TechnologyServiceImpl() {
}
/**
* Singleton method for the service.
*
* @author <a href="mailto:joaom@ciandt.com"> João Felipe de Medeiros
* Moreira </a>
* @since 07/10/2015
*
* @return TechnologyServiceImpl instance.
*/
public static TechnologyServiceImpl getInstance() {
if (instance == null) {
instance = new TechnologyServiceImpl();
}
return instance;
}
/*
* Methods --------------------------------------------
*/
@Override
public Technology addOrUpdateTechnology(Technology technology, User user)
throws BadRequestException, IOException, GeneralSecurityException {
Technology foundTechnology = validateInformations(technology);
Boolean isUpdate = foundTechnology != null && foundTechnology.getId().equals(technology.getId())
&& foundTechnology.getActive().equals(Boolean.TRUE);
String imageLink = saveImage(technology);
if (isUpdate) {
updateTechnology(foundTechnology, technology, user, imageLink);
} else {
addTechnology(technology, user, imageLink);
}
return technology;
}
private void updateTechnology(Technology foundTechnology, Technology technology, User user, String imageLink) {
foundTechnology.setImage(imageLink);
foundTechnology.setDescription(technology.getDescription());
foundTechnology.setShortDescription(technology.getShortDescription());
foundTechnology.setWebsite(technology.getWebsite());
foundTechnology.setLastActivity(new Date());
foundTechnology.setLastActivityUser(getSafeEmail(user));
foundTechnology.setIdBoard(technology.getIdBoard());
technologyDAO.update(foundTechnology);
}
private void addTechnology(Technology technology, User user, String imageLink) {
technology.setId(technology.convertNameToId(technology.getName()));
technology.setAuthor(getSafeEmail(user));
technology.setActive(Boolean.TRUE);
technology.setCreationDate(new Date());
technology.setLastActivity(new Date());
technology.setImage(imageLink);
technology.initCounters();
technologyDAO.add(technology);
}
private String saveImage(Technology technology) throws IOException, GeneralSecurityException {
String imageLink = technology.getImage();
if (technology.getImageContent() != null) {
imageLink = storageDAO.insertImage(technology.convertNameToId(technology.getName()),
new ByteArrayInputStream(DatatypeConverter.parseBase64Binary(technology.getImageContent())));
}
return imageLink;
}
private String getSafeEmail(User user) {
if (user != null) {
return user.getEmail();
}
return null;
}
/**
* Method to validade informations of the technology to be added.
*
* @author <a href="mailto:joaom@ciandt.com"> João Felipe de Medeiros
* Moreira </a>
* @since 13/10/2015
*
* @param technology
* to be validated.
*
* @throws BadRequestException
* in case a request with problem were made.
*/
private Technology validateInformations(Technology technology) throws BadRequestException {
if (StringUtils.isBlank(technology.getId())) {
throw new BadRequestException(ValidationMessageEnums.TECHNOLOGY_ID_CANNOT_BLANK.message());
} else if (StringUtils.isBlank(technology.getName())) {
throw new BadRequestException(ValidationMessageEnums.TECHNOLOGY_NAME_CANNOT_BLANK.message());
} else if (StringUtils.isBlank(technology.getShortDescription())) {
throw new BadRequestException(ValidationMessageEnums.TECHNOLOGY_SHORT_DESCRIPTION_BLANK.message());
} else if (StringUtils.isBlank(technology.getDescription())) {
throw new BadRequestException(ValidationMessageEnums.TECHNOLOGY_DESCRIPTION_BLANK.message());
}
Technology dbTechnology = technologyDAO.findByName(technology.getName());
if (dbTechnology != null && technology.getId() == null) {
throw new BadRequestException(ValidationMessageEnums.TECHNOLOGY_NAME_ALREADY_USED.message());
}
if (technology.getId() != null && dbTechnology != null && !dbTechnology.getName().equals(technology.getName())) {
throw new BadRequestException(ValidationMessageEnums.TECHNOLOGY_NAME_CANNOT_CHANGE.message());
}
return dbTechnology;
}
/**
* GET for getting all technologies.
*
* @throws NotFoundException
* .
*/
@Override
public Response getTechnologies(User user)
throws InternalServerErrorException, NotFoundException, BadRequestException {
List<Technology> techEntities = technologyDAO.findAllActives();
// if list is null, return a not found exception
if (techEntities == null || techEntities.isEmpty()) {
return new TechnologiesResponse();
} else {
verifyTechnologyFollowedByUser(user, techEntities);
TechnologiesResponse response = new TechnologiesResponse();
Technology.sortTechnologiesDefault(techEntities);
response.setTechnologies(techEntities);
return response;
}
}
private List<Technology> setDateFilteredList(List<Technology> completeList, Date dateReference) {
List<Technology> dateFilteredList = new ArrayList<>();
for (Technology technology : completeList) {
if (technology.getLastActivity().after(dateReference) || technology.getLastActivity().equals(dateReference)) {
dateFilteredList.add(technology);
}
}
return dateFilteredList;
}
private Date setDateReference(Date currentDate, int daysToSubtract) {
Calendar cal = Calendar.getInstance();
cal.setTime(currentDate);
cal.add(Calendar.DATE, daysToSubtract);
Date dateReference = cal.getTime();
return dateReference;
}
@Override
public Response findTechnologiesByFilter(TechnologyFilter techFilter, User user)
throws InternalServerErrorException, NotFoundException, BadRequestException {
validateUser(user);
if (techFilter.getRecommendationIs() != null
&& techFilter.getRecommendationIs().equals(RecommendationEnums.UNINFORMED.message())) {
techFilter.setRecommendationIs("");
}
List<Technology> completeList = technologyDAO.findAllActives();
completeList = filterByLastActivityDate(techFilter, completeList);
List<Technology> filteredList = new ArrayList<>();
if (StringUtils.isBlank(techFilter.getTitleContains()) && techFilter.getRecommendationIs() == null) {
filteredList.addAll(completeList);
} else {
verifyFilters(techFilter, completeList, filteredList);
}
if (filteredList.isEmpty()) {
return new TechnologiesResponse();
} else {
if (techFilter.getOrderOptionIs() != null && !techFilter.getOrderOptionIs().isEmpty()) {
filteredList = Technology.sortTechnologies(filteredList,
TechnologyOrderOptionEnum.fromString(techFilter.getOrderOptionIs()));
} else {
Technology.sortTechnologiesDefault(filteredList);
}
TechnologiesResponse response = new TechnologiesResponse();
response.setTechnologies(filteredList);
return response;
}
}
private List<Technology> filterByLastActivityDate(TechnologyFilter techFilter, List<Technology> completeList) {
List<Technology> dateFilteredList = new ArrayList<>();
if (techFilter.getDateFilter() != null) {
Date currentDate = new Date();
switch (techFilter.getDateFilter()) {
case LAST_DAY:
Date lastDay = setDateReference(currentDate, -1);
dateFilteredList = setDateFilteredList(completeList, lastDay);
break;
case LAST_7_DAYS:
Date last7Days = setDateReference(currentDate, -7);
dateFilteredList = setDateFilteredList(completeList, last7Days);
break;
case LAST_30_DAYS:
Date last30Days = setDateReference(currentDate, -30);
dateFilteredList = setDateFilteredList(completeList, last30Days);
break;
default:
break;
}
completeList = dateFilteredList;
}
return completeList;
}
private void verifyTechnologyFollowedByUser(User user, List<Technology> filteredList)
throws NotFoundException, BadRequestException, InternalServerErrorException {
TechGalleryUser techUser = userService.getUserByGoogleId(user.getUserId());
if (techUser != null && techUser.getFollowedTechnologyIds() != null && !techUser.getFollowedTechnologyIds().isEmpty()) {
for (Technology technology : filteredList) {
if (techUser.getFollowedTechnologyIds().contains(technology.getId())) {
technology.setFollowedByUser(true);
}
}
}
}
private void verifyFilters(TechnologyFilter techFilter, List<Technology> completeList,
List<Technology> filteredList) {
for (Technology technology : completeList) {
if (verifyTitleAndShortDescriptionFilter(techFilter, technology)) {
if (techFilter.getRecommendationIs() != null) {
if (verifyRecommendationFilter(techFilter, technology)) {
filteredList.add(technology);
} else {
continue;
}
} else {
filteredList.add(technology);
continue;
}
} else if (verifyRecommendationFilter(techFilter, technology) && techFilter.getTitleContains() == null) {
filteredList.add(technology);
continue;
}
}
}
private boolean verifyRecommendationFilter(TechnologyFilter techFilter, Technology technology) {
if (technology.getRecommendation() == null && techFilter.getRecommendationIs() == "") {
return true;
} else if (technology.getRecommendation() != null && techFilter.getRecommendationIs() != null
&& (technology.getRecommendation().toLowerCase().equals(techFilter.getRecommendationIs().toLowerCase())
|| techFilter.getRecommendationIs().toLowerCase()
.equals(RecommendationEnums.ANY.message().toLowerCase()))) {
return true;
}
return false;
}
private boolean verifyTitleAndShortDescriptionFilter(TechnologyFilter techFilter, Technology technology) {
if (techFilter.getTitleContains() != null
&& (technology.getName().toLowerCase().contains(techFilter.getTitleContains().toLowerCase()) || technology
.getShortDescription().toLowerCase().contains(techFilter.getShortDescriptionContains().toLowerCase()))) {
return true;
}
return false;
}
@Override
public Technology getTechnologyById(String id, User user)
throws NotFoundException, BadRequestException, InternalServerErrorException {
Technology tech = technologyDAO.findByIdActive(id);
if (tech == null) {
throw new NotFoundException(ValidationMessageEnums.TECHNOLOGY_NOT_EXIST.message());
} else {
if (user != null) {
TechGalleryUser techUser = userService.getUserByGoogleId(user.getUserId());
if (techUser != null && techUser.getFollowedTechnologyIds() != null && techUser.getFollowedTechnologyIds().contains(tech.getId())) {
tech.setFollowedByUser(true);
}
}
return tech;
}
}
/**
* Validate the user logged in.
*
* @param user
* info about user from google
* @throws InternalServerErrorException
* in case something goes wrong
* @throws NotFoundException
* in case the information are not founded
* @throws BadRequestException
* in case a request with problem were made.
*/
private void validateUser(User user) throws BadRequestException, NotFoundException, InternalServerErrorException {
if (user == null || user.getUserId() == null || user.getUserId().isEmpty()) {
throw new BadRequestException(ValidationMessageEnums.USER_GOOGLE_ENDPOINT_NULL.message());
}
TechGalleryUser techUser = userService.getUserByGoogleId(user.getUserId());
if (techUser == null) {
throw new NotFoundException(ValidationMessageEnums.USER_NOT_EXIST.message());
}
}
@Override
public List<String> getOrderOptions(User user) {
List<String> orderOptions = new ArrayList<String>();
for (TechnologyOrderOptionEnum item : TechnologyOrderOptionEnum.values()) {
orderOptions.add(item.option());
}
return orderOptions;
}
@Override
public void addCommentariesCounter(Technology entity) {
if (entity != null) {
entity.addCommentariesCounter();
}
technologyDAO.update(entity);
}
@Override
public void removeCommentariesCounter(Technology entity) {
if (entity != null) {
entity.removeCommentariesCounter();
}
technologyDAO.update(entity);
}
@Override
public void addRecomendationCounter(Technology entity, Boolean score) {
if (entity == null) {
return;
}
if (score) {
entity.addPositiveRecommendationsCounter();
} else {
entity.addNegativeRecommendationsCounter();
}
technologyDAO.update(entity);
}
@Override
public void removeRecomendationCounter(Technology entity, Boolean score) {
if (entity == null) {
return;
}
if (score) {
entity.removePositiveRecommendationsCounter();
} else {
entity.removeNegativeRecommendationsCounter();
}
technologyDAO.update(entity);
}
@Override
public void updateEdorsedsCounter(Technology technology, Integer size) {
technology.setEndorsersCounter(size);
technologyDAO.update(technology);
}
@Override
public void audit(String technologyId, User user)
throws NotFoundException, BadRequestException, InternalServerErrorException {
Technology technology = getTechnologyById(technologyId, user);
technology.setLastActivity(new Date());
technology.setLastActivityUser(user.getEmail());
technologyDAO.update(technology);
}
@Override
public Technology deleteTechnology(String technologyId, User user)
throws InternalServerErrorException, BadRequestException, NotFoundException, OAuthRequestException {
validateUser(user);
Technology technology = technologyDAO.findById(technologyId);
if (technology == null) {
throw new NotFoundException(ValidationMessageEnums.NO_TECHNOLOGY_WAS_FOUND.message());
}
technology.setActive(Boolean.FALSE);
technology.setLastActivity(new Date());
technology.setLastActivityUser(user.getEmail());
technologyDAO.update(technology);
return technology;
}
}