All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.wallride.service.PostService Maven / Gradle / Ivy
/*
* Copyright 2014 Tagbangers, Inc.
*
* 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.
*/
package org.wallride.service;
import com.google.api.services.analytics.Analytics;
import com.google.api.services.analytics.model.GaData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import org.wallride.autoconfigure.WallRideCacheConfiguration;
import org.wallride.domain.*;
import org.wallride.exception.GoogleAnalyticsException;
import org.wallride.exception.ServiceException;
import org.wallride.model.PostSearchRequest;
import org.wallride.repository.PopularPostRepository;
import org.wallride.repository.PostRepository;
import org.wallride.support.GoogleAnalyticsUtils;
import org.wallride.web.controller.guest.article.ArticleDescribeController;
import org.wallride.web.controller.guest.page.PageDescribeController;
import org.wallride.web.support.BlogLanguageRewriteMatch;
import org.wallride.web.support.BlogLanguageRewriteRule;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.io.IOException;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
*
* @author OGAWA, Takeshi
*/
@Service
@Transactional(rollbackFor=Exception.class)
public class PostService {
@Autowired
private CacheManager cacheManager;
@Autowired
private ServletContext servletContext;
@Autowired
private JobLauncher jobLauncher;
@Autowired
private JobExplorer jobExplorer;
@Autowired
private Job updatePostViewsJob;
@Autowired
private BlogService blogService;
@Autowired
private PostRepository postRepository;
@Autowired
private PopularPostRepository popularPostRepository;
private static Logger logger = LoggerFactory.getLogger(PostService.class);
public List publishScheduledPosts() {
logger.info("Starting public posts of the scheduled");
LocalDateTime now = LocalDateTime.now();
List posts = postRepository.findAllByStatusAndDateLessThanEqual(Post.Status.SCHEDULED, now);
for (Post post : posts) {
post.setStatus(Post.Status.PUBLISHED);
postRepository.saveAndFlush(post);
}
if (!CollectionUtils.isEmpty(posts)) {
cacheManager.getCache(WallRideCacheConfiguration.ARTICLE_CACHE).clear();
cacheManager.getCache(WallRideCacheConfiguration.PAGE_CACHE).clear();
}
return posts;
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void updatePostViews() {
LocalDateTime now = LocalDateTime.now();
Set jobExecutions = jobExplorer.findRunningJobExecutions("updatePostViewsJob");
for (JobExecution jobExecution : jobExecutions) {
LocalDateTime startTime = LocalDateTime.ofInstant(jobExecution.getStartTime().toInstant(), ZoneId.systemDefault());
Duration d = Duration.between(now, startTime);
if (Math.abs(d.toMinutes()) == 0) {
logger.info("Skip processing because the job is running.");
return;
}
}
JobParameters params = new JobParametersBuilder()
.addDate("now", Date.from(now.atZone(ZoneId.systemDefault()).toInstant()))
.toJobParameters();
try {
jobLauncher.run(updatePostViewsJob, params);
} catch (Exception e) {
throw new ServiceException(e);
}
}
/**
*
* @param blogLanguage
* @param type
* @param maxRank
* @see PostService#getPopularPosts(String, PopularPost.Type)
*/
@CacheEvict(value = WallRideCacheConfiguration.POPULAR_POST_CACHE, key = "'list.type.' + #blogLanguage.language + '.' + #type")
public void updatePopularPosts(BlogLanguage blogLanguage, PopularPost.Type type, int maxRank) {
logger.info("Start update of the popular posts");
GoogleAnalytics googleAnalytics = blogLanguage.getBlog().getGoogleAnalytics();
if (googleAnalytics == null) {
logger.info("Configuration of Google Analytics can not be found");
return;
}
Analytics analytics = GoogleAnalyticsUtils.buildClient(googleAnalytics);
WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext, "org.springframework.web.servlet.FrameworkServlet.CONTEXT.guestServlet");
if (context == null) {
logger.info("GuestServlet is not ready yet");
return;
}
final RequestMappingHandlerMapping mapping = context.getBean(RequestMappingHandlerMapping.class);
Map posts = new LinkedHashMap<>();
int startIndex = 1;
int currentRetry = 0;
int totalResults = 0;
do {
try {
LocalDate now = LocalDate.now();
LocalDate startDate;
switch (type) {
case DAILY: startDate = now.minusDays(1); break;
case WEEKLY: startDate = now.minusWeeks(1); break;
case MONTHLY: startDate = now.minusMonths(1); break;
default: throw new ServiceException();
}
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
Analytics.Data.Ga.Get get = analytics.data().ga()
.get(googleAnalytics.getProfileId(), startDate.format(dateTimeFormatter), now.format(dateTimeFormatter), "ga:sessions")
.setDimensions(String.format("ga:pagePath", googleAnalytics.getCustomDimensionIndex()))
.setSort(String.format("-ga:sessions", googleAnalytics.getCustomDimensionIndex()))
.setStartIndex(startIndex)
.setMaxResults(GoogleAnalyticsUtils.MAX_RESULTS);
if (blogLanguage.getBlog().isMultiLanguage()) {
get.setFilters("ga:pagePath=~/" + blogLanguage.getLanguage() + "/");
}
logger.info(get.toString());
final GaData gaData = get.execute();
if (CollectionUtils.isEmpty(gaData.getRows())) {
break;
}
for (List row : gaData.getRows()) {
UriComponents uriComponents = UriComponentsBuilder.fromUriString((String) row.get(0)).build();
MockHttpServletRequest request = new MockHttpServletRequest(servletContext);
request.setRequestURI(uriComponents.getPath());
request.setQueryString(uriComponents.getQuery());
MockHttpServletResponse response = new MockHttpServletResponse();
BlogLanguageRewriteRule rewriteRule = new BlogLanguageRewriteRule(blogService);
BlogLanguageRewriteMatch rewriteMatch = (BlogLanguageRewriteMatch) rewriteRule.matches(request, response);
try {
rewriteMatch.execute(request, response);
} catch (ServletException e) {
throw new ServiceException(e);
} catch (IOException e) {
throw new ServiceException(e);
}
request.setRequestURI(rewriteMatch.getMatchingUrl());
HandlerExecutionChain handler;
try {
handler = mapping.getHandler(request);
} catch (Exception e) {
throw new ServiceException(e);
}
if (!(handler.getHandler() instanceof HandlerMethod)) {
continue;
}
HandlerMethod method = (HandlerMethod) handler.getHandler();
if (!method.getBeanType().equals(ArticleDescribeController.class) && !method.getBeanType().equals(PageDescribeController.class)) {
continue;
}
// Last path mean code of post
String code = uriComponents.getPathSegments().get(uriComponents.getPathSegments().size() - 1);
Post post = postRepository.findOneByCodeAndLanguage(code, rewriteMatch.getBlogLanguage().getLanguage());
if (post == null) {
logger.debug("Post not found [{}]", code);
continue;
}
if (!posts.containsKey(post)) {
posts.put(post, Long.parseLong((String) row.get(1)));
}
if (posts.size() >= maxRank) {
break;
}
}
if (posts.size() >= maxRank) {
break;
}
startIndex += GoogleAnalyticsUtils.MAX_RESULTS;
totalResults = gaData.getTotalResults();
} catch (IOException e) {
logger.warn("Failed to synchronize with Google Analytics", e);
if (currentRetry >= GoogleAnalyticsUtils.MAX_RETRY) {
throw new GoogleAnalyticsException(e);
}
currentRetry++;
logger.info("{} ms to sleep...", GoogleAnalyticsUtils.RETRY_INTERVAL);
try {
Thread.sleep(GoogleAnalyticsUtils.RETRY_INTERVAL);
} catch (InterruptedException ie) {
throw new GoogleAnalyticsException(e);
}
logger.info("Retry for the {} time", currentRetry);
}
} while (startIndex <= totalResults);
popularPostRepository.deleteByType(blogLanguage.getLanguage(), type);
int rank = 1;
for (Map.Entry entry : posts.entrySet()) {
PopularPost popularPost = new PopularPost();
popularPost.setLanguage(blogLanguage.getLanguage());
popularPost.setType(type);
popularPost.setRank(rank);
popularPost.setViews(entry.getValue());
popularPost.setPost(entry.getKey());
popularPostRepository.saveAndFlush(popularPost);
rank++;
}
logger.info("Complete the update of popular posts");
}
public Page getPosts(PostSearchRequest request) {
Pageable pageable = new PageRequest(0, 10);
return getPosts(request, pageable);
}
public Page getPosts(PostSearchRequest request, Pageable pageable) {
return postRepository.search(request, pageable);
}
/**
*
* @param language
* @param type
* @return
* @see PostService#updatePopularPosts(BlogLanguage, PopularPost.Type, int)
*/
@Cacheable(value = WallRideCacheConfiguration.POPULAR_POST_CACHE, key = "'list.type.' + #language + '.' + #type")
public SortedSet getPopularPosts(String language, PopularPost.Type type) {
Specification spec = (root, query, cb) -> {
Join post = (Join) root.fetch(PopularPost_.post);
post.fetch(Post_.cover);
post.fetch(Post_.author);
List predicates = new ArrayList<>();
predicates.add(cb.equal(root.get(PopularPost_.language), language));
predicates.add(cb.equal(root.get(PopularPost_.type), type));
predicates.add(cb.equal(post.get(Post_.status), Post.Status.PUBLISHED));
return cb.and(predicates.toArray(new Predicate[0]));
};
return popularPostRepository.findAll(spec);
}
public Post getPostById(long id, String language) {
return postRepository.findOneByIdAndLanguage(id, language);
}
}