/* ==================================================================
* Created [2009-4-27 下午11:32:55] by Jon.King
* ==================================================================
* TSS
* ==================================================================
* mailTo:jinpujun@hotmail.com
* Copyright (c) Jon.King, 2009-2012
* ==================================================================
*/
package com.jinhe.tss.cms.timer;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import com.jinhe.tss.cms.CMSConstants;
import com.jinhe.tss.cms.dao.IArticleDao;
import com.jinhe.tss.cms.dao.IChannelDao;
import com.jinhe.tss.cms.entity.Article;
import com.jinhe.tss.cms.entity.TimerStrategy;
import com.jinhe.tss.cms.lucene.ArticleContent;
import com.jinhe.tss.cms.lucene.IndexHelper;
import com.jinhe.tss.cms.publish.PublishManger;
import com.jinhe.tss.core.common.progress.Progress;
import com.jinhe.tss.core.common.progress.ProgressManager;
import com.jinhe.tss.core.common.progress.Progressable;
import com.jinhe.tss.core.exception.BusinessException;
import com.jinhe.tss.core.persistence.ICommonDao;
import com.jinhe.tss.core.util.EasyUtils;
import com.jinhe.tss.core.util.FileHelper;
/**
* <p> TimerServiceImpl.java </p>
*
* 实现了进度条接口,执行创建lucene索引和发布文章时将启动进度条。
*/
public class TimerServiceImpl implements TimerService, Progressable {
protected Logger log = Logger.getLogger(TimerServiceImpl.class);
private final static Set<Long> LOCK = Collections.synchronizedSet(new HashSet<Long>());
@Autowired private ICommonDao commonDao;
@Autowired private IChannelDao channelDao;
@Autowired private IArticleDao articleDao;
@Autowired private PublishManger publishManger;
public String excuteStrategy(TimerStrategy strategy) {
synchronized (LOCK) {
Long strategyId = strategy.getId();
Integer type = strategy.getType();
// 给策略进行加锁控制
if (LOCK.contains(strategyId)) {
throw new BusinessException("当前策略正在执行!策略名称 = " + strategy.getName());
}
LOCK.add(strategyId);
log.info("开始执行定时策略【" + strategy.getName() + "】");
int total = 0;
Map<String, Object> paramsMap = new HashMap<String, Object>();
try {
// 执行发布策略,给当前选中的发布策略发布文章
if (CMSConstants.TACTIC_PUBLISH_TYPE.equals(type)) {
paramsMap.put("type", CMSConstants.TACTIC_PUBLISH_TYPE);
String channelIds = strategy.getContent();
total = publishManger.getPublishableArticleCount4TimerJob(channelIds, paramsMap);
}
// 执行索引策略,根据索引策略建立索引文件
if (CMSConstants.TACTIC_INDEX_TYPE.equals(type)) {
paramsMap.put("indexStrategy", strategy);
paramsMap.put("type", CMSConstants.TACTIC_INDEX_TYPE);
Set<ArticleContent> content = IndexHelper.getIndexableArticles4Lucene(strategy, channelDao, articleDao);
paramsMap.put("articleContentSet", content); // 需要建索引的所有文章地址列表
total = content.size();
}
// 执行过期策略:直接执行,不启用进度条(进度长度设为0即可)
if (CMSConstants.TACTIC_EXPIRE_TYPE.equals(type)) {
total = 0;
excuteExpireStrategy(strategy);
}
// 交有进度条管理类另起线程执行策略的执行工作。
return new ProgressManager(this, total, paramsMap).execute();
} catch (RuntimeException e) {
throw new BusinessException("excute Strategy 出错,策略名称 = " + strategy.getName(), e);
} finally {
LOCK.remove(strategyId);
}
}
}
/*
* 执行定时任务时启用进度条。
*/
@SuppressWarnings("unchecked")
public void execute(Map<String, Object> params, final Progress progress) {
Object type = params.get("type");
if(CMSConstants.TACTIC_INDEX_TYPE.equals(type)) { // 创建索引
TimerStrategy tacticIndex = (TimerStrategy) params.get("indexStrategy");
Object content = params.get("articleContentSet");
IndexHelper.createIndex(tacticIndex, (Set<ArticleContent>)content, progress);
}
else if(CMSConstants.TACTIC_PUBLISH_TYPE.equals(type)) {
List<Long> channelIds = (List<Long>) params.get("channelIds");
publishManger.publishArticle4TimerJob(channelIds, progress);
}
else {
// 如果是其它的像过期策略等,进度长度为0,不使用进度条
}
}
/** 文章过期处理(删除已过期的文章生成的xml文件) */
private void excuteExpireStrategy(TimerStrategy strategy) {
List<Article> expireList = new ArrayList<Article>();
// 判断用户对该流程步骤是否有权限
if( articleDao.checkArticleWorkflowPermission(CMSConstants.OVER_STATUS.toString(), CMSConstants.DEFAULT_WORKFLOW_ID) ){
String[] channelIds = strategy.getContent().split(",");
for ( String temp : channelIds ) {
Long channelId = new Long(temp);
expireList.addAll(articleDao.getExpireArticlePuburlList(new Date(), channelId));
}
}
for ( Article article : expireList ) {
article.setStatus(CMSConstants.OVER_STATUS);
String pubUrl = article.getPubUrl();
if ( !EasyUtils.isNullOrEmpty(pubUrl) ) {
FileHelper.deleteFile(new File(pubUrl)); // 删除文章生成的xml文件
}
}
articleDao.flush();
log.info("总共有 " + expireList.size() + " 条文章记录被设置为过期状态。");
}
//*-------------------------------- 定时策略维护(增删改停启用等)----------------------------------------
public List<?> getAllTimerStrategy() {
return commonDao.getEntities("from TimerStrategy order by id");
}
public TimerStrategy getStrategyById(Long strategyId) {
Object strategy = commonDao.getEntity(TimerStrategy.class, strategyId);
if (strategy == null) {
throw new BusinessException("策略ID(" + strategyId + ")在数据库中不存在!");
}
return (TimerStrategy)strategy;
}
public TimerStrategy addTimeStrategy(TimerCondition condition) {
TimerStrategy strategy = condition.getStrategy();
String indexPath = strategy.getIndexPath();
if( !EasyUtils.isNullOrEmpty(indexPath)) {
checkPath(indexPath);
}
strategy.setParentId( CMSConstants.HEAD_NODE_ID );
strategy.setStatus( CMSConstants.STATUS_STOP );
strategy.setType( CMSConstants.TACTIC_TIME_TYPE );
TimerStrategy timerStrategy = (TimerStrategy) commonDao.create(strategy);
if (timerStrategy == null) {
throw new BusinessException("新建时间策略不成功!");
}
if (CMSConstants.TACTIC_TIME_TYPE.equals(timerStrategy.getType())) {
// 创建触发器和定时任务
SchedulerBean.addTriggerAndJob(timerStrategy);
}
return timerStrategy;
}
/**
* 检测输入路径的正确性
*/
private void checkPath(String indexPath) {
File file = new File(indexPath);
if ( file.exists() && file.isDirectory() && file.canWrite()) return;
if( !file.exists() && file.mkdirs()) return;
throw new BusinessException("索引策略的索引路径填写错误,不能生成相应的索引文件路径!");
}
public void removeTimeStrategy(Long strategyId) {
TimerStrategy strategy = getStrategyById(strategyId);
commonDao.delete(strategy);
SchedulerBean.removeTriggerAndJob(strategyId);
//删除时间索引下的其它类型索引
commonDao.deleteAll(getAllStrategysByTimerStrategy(strategyId));
}
public void updateTimeStrategy(TimerCondition condition) {
TimerStrategy timeStrategy = condition.getStrategy();
TimerStrategy oldTimeStrategy = getStrategyById(timeStrategy.getId());
if (CMSConstants.TACTIC_TIME_TYPE.equals(timeStrategy.getType())) {
SchedulerBean.removeTriggerAndJob(timeStrategy.getId());
// 新建时间策略失败后,新建以前的时间策略
SchedulerBean.editTriggerAndJob(timeStrategy, oldTimeStrategy);
}
oldTimeStrategy.setName(timeStrategy.getName());
oldTimeStrategy.setIndexPath(timeStrategy.getIndexPath());
oldTimeStrategy.setContent(timeStrategy.getContent()); // 定时时间
commonDao.update(oldTimeStrategy);
}
public void startTimeStrategy(Long strategyId) {
changeTimeStrategyStatus(strategyId, CMSConstants.STATUS_START);
SchedulerBean.startScheduler(strategyId);
}
public void stopTimeStrategy(Long strategyId) {
changeTimeStrategyStatus(strategyId, CMSConstants.STATUS_STOP);
SchedulerBean.stopScheduler(strategyId);
}
private void changeTimeStrategyStatus(Long timeStrategyId, Integer status){
TimerStrategy timeStrategy = getStrategyById(timeStrategyId);
timeStrategy.setStatus(status);
commonDao.update(timeStrategy);
List<?> strategyList = getAllStrategysByTimerStrategy(timeStrategy.getId());
for (int i = 0; i < strategyList.size(); i++) {
TimerStrategy strategy = (TimerStrategy) strategyList.get(i);
if ( !status.equals(strategy.getStatus()) ) {
strategy.setStatus(status);
commonDao.update(strategy);
}
}
}
/**
* 获取定时策略下挂着的所有策略。
*/
private List<?> getAllStrategysByTimerStrategy(Long timerStrategyId) {
return commonDao.getEntities("from TimerStrategy t where t.parentId = ? order by t.id", timerStrategyId);
}
// ----------------------------- 以下操作的是定时策略的子策略,比如索引策略、发布策略、过期策略等 -----------------------------
public TimerStrategy addStrategy(TimerCondition condition) {
TimerStrategy strategyInCondition = condition.getStrategy();
TimerStrategy timeStrategy = getStrategyById(condition.getParentId());
strategyInCondition.setStatus(timeStrategy.getStatus());
strategyInCondition.setParentId(timeStrategy.getId());
TimerStrategy tacticIndex = (TimerStrategy) commonDao.create(strategyInCondition);
if (tacticIndex == null)
throw new BusinessException("新建索引策略不成功!");
return tacticIndex;
}
public void removeStrategy(Long tacticId) {
commonDao.delete(getStrategyById(tacticId));
}
public void updateTacticIndexAndPublish(TimerCondition condition) {
TimerStrategy strategyInCondition = condition.getStrategy();
TimerStrategy strategy = getStrategyById(strategyInCondition.getId());
strategy.setName(strategyInCondition.getName());
strategy.setIndexExecutorClass(strategyInCondition.getIndexExecutorClass());
strategy.setRemark(strategyInCondition.getRemark());
if(strategyInCondition.getContent() != null){
strategy.setContent(strategyInCondition.getContent());
}
commonDao.update(strategy);
}
public void startStrategy(Long strategyId) {
TimerStrategy strategy = getStrategyById(strategyId);
TimerStrategy timeStrategy = getStrategyById(strategy.getParentId());
if (CMSConstants.STATUS_STOP.equals(timeStrategy.getStatus())) {
throw new BusinessException("策略所属的时间策略处于停用状态,请先启用时间策略!");
}
strategy.setStatus(CMSConstants.STATUS_START);
commonDao.update(strategy);
}
public void stopStrategy(Long strategyId) {
TimerStrategy strategy = getStrategyById(strategyId);
strategy.setStatus(CMSConstants.STATUS_STOP);
commonDao.update(strategy);
}
public Object[] getStrategyAndChannels(Long strategyId) {
TimerStrategy strategy;
if(strategyId != null)
strategy = getStrategyById(strategyId);
else
strategy = new TimerStrategy();
return new Object[]{strategy, channelDao.getAllStartedSiteChannelList()};
}
public List<?> getEntities(String hql, Object...conditionValues) {
return commonDao.getEntities(hql, conditionValues);
}
}