/*
* Copyright 2015-Present Entando Inc. (http://www.entando.com) All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.agiletec.plugins.jpblog.aps.system.services.blog;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.agiletec.aps.system.common.AbstractService;
import com.agiletec.aps.system.common.entity.ApsEntityManager;
import com.agiletec.aps.system.common.entity.model.EntitySearchFilter;
import com.agiletec.aps.system.common.entity.model.IApsEntity;
import com.agiletec.aps.system.common.entity.model.attribute.DateAttribute;
import com.agiletec.aps.system.exception.ApsSystemException;
import com.agiletec.aps.system.services.baseconfig.ConfigInterface;
import com.agiletec.aps.system.services.category.Category;
import com.agiletec.aps.system.services.category.ICategoryManager;
import com.agiletec.aps.system.services.group.Group;
import com.agiletec.aps.system.services.group.IGroupManager;
import com.agiletec.aps.util.DateConverter;
import com.agiletec.plugins.jacms.aps.system.services.content.IContentManager;
import com.agiletec.plugins.jacms.aps.system.services.content.model.Content;
import com.agiletec.plugins.jpblog.aps.system.JpblogSystemConstants;
import com.agiletec.plugins.jpblog.aps.system.services.blog.model.GroupStatistic;
import com.agiletec.plugins.jpblog.aps.system.services.blog.util.BlogStatisticsUtil;
@Aspect
public class BlogManager extends AbstractService implements IBlogManager {
private static final Logger _logger = LoggerFactory.getLogger(BlogManager.class);
@Override
public void init() throws Exception {
this.loadConfigs();
this.loadArchive();
_logger.debug("{} ready", this.getClass().getName());
}
protected void loadConfigs() throws ApsSystemException {
try {
ConfigInterface configManager = this.getConfigManager();
String xml = configManager.getConfigItem(JpblogSystemConstants.CONFIG_ITEM);
if (xml == null) {
throw new ApsSystemException("Configuration item not present: " + JpblogSystemConstants.CONFIG_ITEM);
}
this.setConfig(new BlogConfig(xml));
} catch (Throwable t) {
_logger.error("Error loading config", t);
throw new ApsSystemException("Error loading config", t);
}
}
protected void loadArchive() throws ApsSystemException {
try {
IContentManager contentManager = this.getContentManager();
List<String> contents = this.loadContentIds();
_logger.debug("Found {} for Blog archive", contents.size());
Map<String, Map<String, List<GroupStatistic>>> archive = new HashMap<String, Map<String,List<GroupStatistic>>>();
Iterator<String> contentIds = contents.iterator();
while (contentIds.hasNext()) {
String contentId = contentIds.next();
Content content = contentManager.loadContent(contentId, true);
Map<String, List<GroupStatistic>> typeCodeArchive = this.extractArchive(content.getTypeCode(), archive);
this.addOccurrenceToArchive(content, typeCodeArchive);
}
this.setArchive(archive);
// this.printCompleteArchive(archive);
} catch (Throwable t) {
_logger.error("Error loading archive statistics", t);
throw new ApsSystemException("Errore loading archive statistics", t);
}
}
/*
private void printCompleteArchive(Map<String, Map<String, List<GroupStatistic>>> archive) {
Iterator<Entry<String, Map<String, List<GroupStatistic>>>> archiveIter = archive.entrySet().iterator();
while (archiveIter.hasNext()) {
Entry<String, Map<String, List<GroupStatistic>>> entry = archiveIter.next();
System.out.println("TypeCode: " + entry.getKey());
this.printArchive(entry.getValue());
}
}
private void printArchive(Map<String, List<GroupStatistic>> archive) {
Iterator<Entry<String, List<GroupStatistic>>> archiveIter = archive.entrySet().iterator();
while (archiveIter.hasNext()) {
Entry<String, List<GroupStatistic>> monthStat = archiveIter.next();
System.out.println("MONTH: " + monthStat.getKey());
Iterator<GroupStatistic> groupStatsIter = monthStat.getValue().iterator();
while (groupStatsIter.hasNext()) {
GroupStatistic groupStat = groupStatsIter.next();
System.out.println("OCCURRENCES: " + groupStat.getOccurrences() + " - GROUPS: " + groupStat.getGroups());
}
}
}
//*/
public void updateConfig(IBlogConfig config) throws ApsSystemException {
try {
String xml = config.toXML();
this.getConfigManager().updateConfigItem(JpblogSystemConstants.CONFIG_ITEM, xml);
this.setConfig(config);
} catch (Throwable t) {
_logger.error("Error updating blog config", t);
throw new ApsSystemException("Error updating blog config", t);
}
}
@Override
public List<BlogArchiveInfoBean> getOccurrencesByDate(String contentType, List<String> groupCodes) throws ApsSystemException {
try {
List<BlogArchiveInfoBean> list = new ArrayList<BlogArchiveInfoBean>();
Map<String, List<GroupStatistic>> archive = this.extractArchive(contentType, this.getArchive());
Iterator<Entry<String, List<GroupStatistic>>> archiveIter = archive.entrySet().iterator();
while (archiveIter.hasNext()) {
Entry<String, List<GroupStatistic>> monthStat = archiveIter.next();
int occurrences = BlogStatisticsUtil.getOccurrences(groupCodes, monthStat.getValue());
if (occurrences>0) {
BlogArchiveInfoBean info = new BlogArchiveInfoBean();
info.setGroupNames(groupCodes);
String monthKey = monthStat.getKey();
info.setYear(monthKey.substring(0, 4));
info.setMonth(monthKey.substring(5, 7));
info.setOccurrences(occurrences);
list.add(info);
}
}
// return this.getBlogDAO().getOccurrenceByDate(contentType, groupCodes);
return list;
} catch (Throwable t) {
_logger.error("Errore loading OccurrencesByDate", t);
throw new ApsSystemException("Errore in caricamento getOccurrencesByDate ");
}
}
public List<String> getSpecialCategories() {
List<String> catCodes = new ArrayList<String>();
try {
catCodes = this.getConfig().getCategories();
if (null == catCodes || catCodes.size() == 0) {
catCodes.add(this.getCategoryManager().getRoot().getCode());
} else {
catCodes = catCodes.subList(0, 1);
}
/*
String catConfig = this.getConfigManager().getParam(JpblogSystemConstants.CONFIG_PARAM_BLOG_CATEGORIES);
if (null != catConfig && catConfig.trim().length() > 0) {
String[] code = catConfig.split(",");
for (int i = 0; i < code.length; i++) {
catCodes.add(code[i].trim());
}
}
*/
} catch (Throwable t) {
_logger.error("Error loadng SpecialCategories", t);
throw new RuntimeException("Errore in caricamento SpecialCategories");
}
return catCodes;
}
@Override
public Map<Category, Integer> getOccurrences(List<String> contentTypeCodes, List<String> facetNodeCodes, List<String> groupCodes) throws ApsSystemException {
Map<Category, Integer> occurrence = null;
try {
List<String> facetNodeCodes2 = new ArrayList<String>(facetNodeCodes);
String categoryRootCode = this.getCategoryManager().getRoot().getCode();
//se non esiste nessuna categoria specifica per il blog, la categoria di referimento è la root delle categorie
//in questo caso, per la costruzione dello stat, NON deve essere passato il codice..
//serve per far si che quando esiste una o più facetNodecodes lo stat sia ....WHERE contentrelations.refcategory = 'code'
//ma quando nel blog non è settata nessuna categoria lo sta deve essere --....WHERE contentrelations.refcategory is not null.
//perchè la categoria root NON viene scritta in contentrelations
if (facetNodeCodes2.contains(categoryRootCode)) {
facetNodeCodes2.remove(categoryRootCode);
}
Map<String, Integer> allOccurrence = this.getBlogDAO().getOccurrences(contentTypeCodes, facetNodeCodes2, groupCodes);
if (null != allOccurrence) {
occurrence = this.purgeMap(allOccurrence, facetNodeCodes, this.getCategoryManager(), null);
}
} catch (Throwable t) {
_logger.error("Error loading occurrences", t);
throw new ApsSystemException("Error loading occurrences", t);
}
return occurrence;
}
@Override
public Map<Category, Integer> getOccurrences(List<String> contentTypeCodes, List<String> groupCodes) throws ApsSystemException {
Map<Category, Integer> occurrence = null;
try {
List<String> facetNodeCodes = new ArrayList<String>(this.getSpecialCategories());
String categoryRootCode = this.getCategoryManager().getRoot().getCode();
//se non esiste nessuna categoria specifica per il blog, la categoria di referimento è la root delle categorie
//in questo caso, per la costruzione dello stat, NON deve essere passato il codice..
//serve per far si che quando esiste una o più facetNodecodes lo stat sia ....WHERE contentrelations.refcategory = 'code'
//ma quando nel blog non è settata nessuna categoria lo sta deve essere --....WHERE contentrelations.refcategory is not null.
//perchè la categoria root NON viene scritta in contentrelations
if (facetNodeCodes.contains(categoryRootCode)) {
facetNodeCodes.remove(categoryRootCode);
}
Map<String, Integer> allOccurrence = this.getBlogDAO().getOccurrences(contentTypeCodes, facetNodeCodes, groupCodes);
if (null != allOccurrence) {
occurrence = this.purgeMap(allOccurrence, this.getSpecialCategories(), this.getCategoryManager(), null);
}
} catch (Throwable t) {
_logger.error("Error loading occurrences", t);
throw new ApsSystemException("Error loading occurrences", t);
}
return occurrence;
}
/**
* Elimina dei risultati le categorie che non sono sui rami SpecialCategories.
* Inoltre elimina tutte le categorie che NON sono foglia
* @param occurrences
* @param facetNodeCodes
*/
/*private Map<Category, Integer> purgeMap(Map<String, Integer> occurrences, List<String> facetNodeCodes, ICategoryManager categoryManager) {
Map<Category, Integer> purgedMap = new HashMap<Category, Integer>();
for (Map.Entry<String, Integer> entry : occurrences.entrySet()) {
String currentCat = entry.getKey();
Category cat = categoryManager.getCategory(currentCat);
boolean ok = false;
if (null != cat) {
for (int i = 0; i < facetNodeCodes.size(); i++) {
String specialCatRootCode = facetNodeCodes.get(i);
if (cat.isChildOf(specialCatRootCode) && cat.getChildren().length == 0) {
ok = true;
break;
}
}
}
if (ok) {
purgedMap.put(cat, entry.getValue());
}
}
return purgedMap;
}
*/
private Map<Category, Integer> purgeMap(Map<String, Integer> occurrences, List<String> facetNodeCodes, ICategoryManager categoryManager, Boolean onnyLeafs) {
Map<Category, Integer> purgedMap = new HashMap<Category, Integer>();
for (Map.Entry<String, Integer> entry : occurrences.entrySet()) {
String currentCat = entry.getKey();
Category cat = categoryManager.getCategory(currentCat);
boolean ok = false;
if (null != cat) {
for (int i = 0; i < facetNodeCodes.size(); i++) {
String specialCatRootCode = facetNodeCodes.get(i);
boolean checkLeafs = null == onnyLeafs || !onnyLeafs.booleanValue() || (onnyLeafs.booleanValue() && cat.getChildren().length == 0);
if (cat.isChildOf(specialCatRootCode) && checkLeafs) {
ok = true;
break;
}
}
}
if (ok) {
purgedMap.put(cat, entry.getValue());
}
}
return purgedMap;
}
// INIZIO - Metodi per gestione Archivio
@Before("execution(* com.agiletec.plugins.jacms.aps.system.services.content.IContentManager.insertOnLineContent(..)) && args(content)")
public void listenContentPublishing(Content content) {
try {
Object attribute = content.getAttributeByRole(JpblogSystemConstants.ATTRIBUTE_ROLE_DATE);
if (attribute!=null && attribute instanceof DateAttribute) {
Date newDate = ((DateAttribute) attribute).getDate();
Map<String, List<GroupStatistic>> archive = this.extractArchive(content.getTypeCode(), this.getArchive());
Content oldContent = this.getContentManager().loadContent(content.getId(), true);
if (oldContent==null) {// INSERT
Set<String> groups = this.extractContentGroups(content);
this.addOccurrenceToArchive(newDate, groups, content, archive);
} else {// UPDATE
this.updateOccurrenceToArchive(newDate, content, oldContent, archive);
}
}
} catch (Throwable t) {
_logger.error("error in listenContentPublishing", t);
// Non rilancia niente
}
}
@Before("execution(* com.agiletec.plugins.jacms.aps.system.services.content.IContentManager.removeOnLineContent(..)) && args(content)")
public void listenContentRemoving(Content content) {
try {
Object attribute = content.getAttributeByRole(JpblogSystemConstants.ATTRIBUTE_ROLE_DATE);
if (attribute!=null && attribute instanceof DateAttribute) {
Content oldContent = this.getContentManager().loadContent(content.getId(), true);
if (oldContent!=null) {// REMOVE
Map<String, List<GroupStatistic>> archive = this.extractArchive(content.getTypeCode(), this.getArchive());
Date oldDate = this.extractContentDate(oldContent);
Set<String> oldGroups = this.extractContentGroups(oldContent);
this.removeOccurrenceToArchive(oldDate, oldGroups, oldContent, archive);
}
}
} catch (Throwable t) {
_logger.error("error in listenContentRemoving", t);
// Non rilancia niente
}
}
// @Override
// public void updateFromPublicContentChanged(PublicContentChangedEvent event) {
// try {
// Content content = event.getContent();
// Object attribute = content.getAttributeByRole(JpblogSystemConstants.ATTRIBUTE_ROLE_DATE);
// if (attribute!=null && attribute instanceof DateAttribute) {
// Date date = ((DateAttribute) attribute).getDate();
// Map<String, List<GroupStatistic>> archive = this.extractArchive(content.getTypeCode(), this.getArchive());
// int operationCode = event.getOperationCode();
// if (operationCode==PublicContentChangedEvent.INSERT_OPERATION_CODE) {
// Set<String> groups = this.extractContentGroups(content);
// this.addOccurrenceToArchive(date, groups, archive);
// } else if (operationCode==PublicContentChangedEvent.REMOVE_OPERATION_CODE) {
// Content oldContent = this.getContentManager().loadContent(content.getId(), true);
// Set<String> groups = this.extractContentGroups(oldContent);
// this.removeOccurrenceToArchive(date, groups, archive);
// } else {// UPDATE
//// this.updateOccurrenceToArchive(date, content, archive);
// }
// this.printCompleteArchive(this.getArchive());
// }
// } catch (Throwable t) {
// ApsSystemUtils.logThrowable(t, this, "updateFromPublicContentChanged");
// // Non rilancia niente
// }
// }
private Date extractContentDate(Content content) {
Date date = null;
Object attribute = content.getAttributeByRole(JpblogSystemConstants.ATTRIBUTE_ROLE_DATE);
if (attribute!=null && attribute instanceof DateAttribute) {
date = ((DateAttribute) attribute).getDate();
}
return date;
}
private List<String> loadContentIds() throws ApsSystemException {
List<Object> typeCodes = new ArrayList<Object>();
Iterator<IApsEntity> prototypes = this.getContentManager().getEntityPrototypes().values().iterator();
while (prototypes.hasNext()) {
IApsEntity prototype = prototypes.next();
if (prototype.getAttributeByRole(JpblogSystemConstants.ATTRIBUTE_ROLE_DATE)!=null) {
typeCodes.add(prototype.getTypeCode());
}
}
if (typeCodes.size()>0) {
EntitySearchFilter typeCodeFilter = new EntitySearchFilter(ApsEntityManager.ENTITY_TYPE_CODE_FILTER_KEY, false, typeCodes, false);
EntitySearchFilter[] filters = { typeCodeFilter };
List<Group> groups = this.getGroupManager().getGroups();
List<String> groupCodes = new ArrayList<String>(groups.size());
Iterator<Group> groupsIter = groups.iterator();
while (groupsIter.hasNext()) {
groupCodes.add(groupsIter.next().getAuthority());
}
return this.getContentManager().loadPublicContentsId(null, filters, groupCodes);
}
return new ArrayList<String>();
}
private void removeOccurrenceToArchive(Date date, Set<String> groups, Content content, Map<String, List<GroupStatistic>> archive) {
if (date!=null) {
String dateKey = DateConverter.getFormattedDate(date, MONTH_FORMAT_KEY);
List<GroupStatistic> groupStatistics = archive.get(dateKey);
if (groupStatistics!=null) {
BlogStatisticsUtil.removeOccurrence(groups, groupStatistics);
if (groupStatistics.isEmpty()) {
archive.remove(dateKey);
}
_logger.debug("Removec occurrences for Content: {}", content.getId());
}
}
}
private void updateOccurrenceToArchive(Date newDate, Content newContent, Content oldContent, Map<String, List<GroupStatistic>> archive) throws ApsSystemException {
Date oldDate = this.extractContentDate(oldContent);
Set<String> groups = this.extractContentGroups(newContent);
Set<String> oldGroups = this.extractContentGroups(oldContent);
if (((newDate!=null || oldDate!=null) && (newDate==null || oldDate==null || newDate.compareTo(oldDate)!=0)) ||
(groups.size()!=oldGroups.size() || !groups.containsAll(oldGroups))) {
this.removeOccurrenceToArchive(oldDate, oldGroups, oldContent, archive);
this.addOccurrenceToArchive(newDate, groups, newContent, archive);
}
}
private void addOccurrenceToArchive(Date date, Set<String> groups, Content content, Map<String, List<GroupStatistic>> archive) {
if (date!=null) {
String dateKey = DateConverter.getFormattedDate(date, MONTH_FORMAT_KEY);
List<GroupStatistic> groupStatistics = archive.get(dateKey);
if (groupStatistics==null) {
groupStatistics = new ArrayList<GroupStatistic>();
archive.put(dateKey, groupStatistics);
}
BlogStatisticsUtil.addOccurrence(groups, groupStatistics);
_logger.debug("Added occurrences for Content: {}", content.getId());
}
}
private void addOccurrenceToArchive(Content content, Map<String, List<GroupStatistic>> archive) {
Object attribute = content.getAttributeByRole(JpblogSystemConstants.ATTRIBUTE_ROLE_DATE);
if (attribute!=null && attribute instanceof DateAttribute) {
Date date = ((DateAttribute) attribute).getDate();
// ApsSystemUtils.getLogger().info("Date: " + date);
if (date!=null) {
Set<String> groups = this.extractContentGroups(content);
// ApsSystemUtils.getLogger().info("Groups: " + groups);
this.addOccurrenceToArchive(date, groups, content, archive);
}
}
}
private Set<String> extractContentGroups(Content content) {
Set<String> groups = new TreeSet<String>(content.getGroups());
groups.add(content.getMainGroup());
return groups;
}
// FINE - Metodi per gestione Archivio
protected Map<String, List<GroupStatistic>> extractArchive(String typeCode, Map<String, Map<String, List<GroupStatistic>>> archive) {
Map<String, List<GroupStatistic>> typeCodeArchive = archive.get(typeCode);
if (typeCodeArchive==null) {
typeCodeArchive = new TreeMap<String, List<GroupStatistic>>();
archive.put(typeCode, typeCodeArchive);
}
return typeCodeArchive;
}
protected Map<String, Map<String, List<GroupStatistic>>> getArchive() {
return _archive;
}
protected void setArchive(Map<String, Map<String, List<GroupStatistic>>> archive) {
this._archive = archive;
}
public IBlogConfig getConfig() {
return _config;
}
public void setConfig(IBlogConfig config) {
this._config = config;
}
public void setConfigManager(ConfigInterface configManager) {
this._configManager = configManager;
}
protected ConfigInterface getConfigManager() {
return _configManager;
}
public void setBlogDAO(IBlogDAO blogDAO) {
this._blogDAO = blogDAO;
}
protected IBlogDAO getBlogDAO() {
return _blogDAO;
}
public void setCategoryManager(ICategoryManager categoryManager) {
this._categoryManager = categoryManager;
}
protected ICategoryManager getCategoryManager() {
return _categoryManager;
}
protected IContentManager getContentManager() {
return _contentManager;
}
public void setContentManager(IContentManager contentManager) {
this._contentManager = contentManager;
}
protected IGroupManager getGroupManager() {
return _groupManager;
}
public void setGroupManager(IGroupManager groupManager) {
this._groupManager = groupManager;
}
private ICategoryManager _categoryManager;
private IBlogDAO _blogDAO;
private ConfigInterface _configManager;
private IContentManager _contentManager;
private IGroupManager _groupManager;
private IBlogConfig _config;
private Map<String, Map<String, List<GroupStatistic>>> _archive;
private final String MONTH_FORMAT_KEY = "yyyy-MM";
}