/* * * Copyright 2013 Entando S.r.l. (http://www.entando.com) All rights reserved. * * This file is part of Entando software. * Entando is a free software; * You can redistribute it and/or modify it * under the terms of the GNU General Public License (GPL) as published by the Free Software Foundation; version 2. * * See the file License for the specific language governing permissions * and limitations under the License * * * * Copyright 2013 Entando S.r.l. (http://www.entando.com) All rights reserved. * */ package com.agiletec.plugins.jprss.aps.system.services.rss; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.agiletec.aps.system.ApsSystemUtils; import com.agiletec.aps.system.RequestContext; import com.agiletec.aps.system.common.AbstractService; import com.agiletec.aps.system.common.entity.event.EntityTypesChangingEvent; import com.agiletec.aps.system.common.entity.event.EntityTypesChangingObserver; 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.AttributeInterface; import com.agiletec.aps.system.common.entity.model.attribute.ITextAttribute; import com.agiletec.aps.system.exception.ApsSystemException; import com.agiletec.aps.system.services.baseconfig.ConfigInterface; import com.agiletec.aps.system.services.group.Group; import com.agiletec.aps.system.services.keygenerator.IKeyGeneratorManager; import com.agiletec.aps.system.services.page.IPageManager; import com.agiletec.plugins.jacms.aps.system.JacmsSystemConstants; 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.jacms.aps.system.services.content.model.ContentRecordVO; import com.agiletec.plugins.jacms.aps.system.services.content.model.SmallContentType; import com.agiletec.plugins.jacms.aps.system.services.content.model.SymbolicLink; import com.agiletec.plugins.jacms.aps.system.services.content.widget.util.EntitySearchFilterDOM; import com.agiletec.plugins.jacms.aps.system.services.linkresolver.ILinkResolverManager; import com.agiletec.plugins.jprss.aps.system.services.JpRssSystemConstants; import com.sun.syndication.feed.synd.SyndContent; import com.sun.syndication.feed.synd.SyndContentImpl; import com.sun.syndication.feed.synd.SyndEntry; import com.sun.syndication.feed.synd.SyndEntryImpl; import com.sun.syndication.feed.synd.SyndFeed; import com.sun.syndication.feed.synd.SyndFeedImpl; /** * Manager that handles the Channels */ public class RssManager extends AbstractService implements IRssManager, EntityTypesChangingObserver { @Override public void init() throws Exception { this.loadMappingConfig(); ApsSystemUtils.getLogger().debug(this.getClass().getName() + ": initialized"); } @Override public void updateFromEntityTypesChanging(EntityTypesChangingEvent event) { if (!event.getEntityManagerName().equals(JacmsSystemConstants.CONTENT_MANAGER)) { return; } try { this.loadMappingConfig(); } catch (Throwable t) { ApsSystemUtils.logThrowable(t, this, "addChannel", "error loading Rss Content Config"); } } private void loadMappingConfig() throws ApsSystemException { Map<String, RssContentMapping> mappings = new HashMap<String, RssContentMapping>(); try { Map<String, IApsEntity> contentTypes = this.getContentManager().getEntityPrototypes(); Iterator<IApsEntity> contentTypeIter = contentTypes.values().iterator(); while (contentTypeIter.hasNext()) { IApsEntity contentType = contentTypeIter.next(); AttributeInterface attributeTitle = contentType.getAttributeByRole(JpRssSystemConstants.ATTRIBUTE_ROLE_RSS_CONTENT_TITLE); if (null != attributeTitle) { RssContentMapping mapping = new RssContentMapping(); mapping.setContentType(contentType.getTypeCode()); mapping.setTitleAttributeName(attributeTitle.getName()); AttributeInterface attributeDescr = contentType.getAttributeByRole(JpRssSystemConstants.ATTRIBUTE_ROLE_RSS_CONTENT_DESCRIPTION); if (null != attributeDescr) { mapping.setDescriptionAttributeName(attributeDescr.getName()); } mappings.put(contentType.getTypeCode(), mapping); } } } catch (Throwable t) { ApsSystemUtils.logThrowable(t, this, "loadMappingConfig"); throw new ApsSystemException("Error loading rss content mapping", t); } this.setContentMapping(mappings); } @Override public void addChannel(Channel channel) throws ApsSystemException { try { int key = getKeyGeneratorManager().getUniqueKeyCurrentValue(); channel.setId(key); this.getRssDAO().addChannel(channel); } catch (Throwable t) { ApsSystemUtils.logThrowable(t, this, "addChannel"); throw new ApsSystemException("Error adding a new channel", t); } } @Override public void deleteChannel(int id) throws ApsSystemException { try { this.getRssDAO().deleteChannel(id); } catch (Throwable t) { ApsSystemUtils.logThrowable(t, this, "deleteChannel"); throw new ApsSystemException("Error deleting the channel with code: " + id, t); } } @Override public void updateChannel(Channel channel) throws ApsSystemException { try { this.getRssDAO().updateChannel(channel); } catch (Throwable t) { ApsSystemUtils.logThrowable(t, this, "updateChannel"); throw new ApsSystemException("Error updating a channel", t); } } @Override public List<Channel> getChannels(int status) throws ApsSystemException { List<Channel> channels = null; try { channels = this.getRssDAO().getChannels(status); } catch (Throwable t) { ApsSystemUtils.logThrowable(t, this, "getChannels"); throw new ApsSystemException("Error getting the list of the channels", t); } return channels; } @Override public Channel getChannel(int id) throws ApsSystemException { Channel channel = null; try { channel = this.getRssDAO().getChannel(id); } catch (Throwable t) { ApsSystemUtils.logThrowable(t, this, "getChannel"); throw new ApsSystemException("Error loading channel with id" + id,t); } return channel; } private EntitySearchFilter[] getEntitySearchFilter(Channel channel, String langCode) { String contentType = channel.getContentType(); String showletParam = channel.getFilters(); EntitySearchFilter[] entitySearchFilters = null; if (null!=showletParam && showletParam.trim().length()>0) { EntitySearchFilterDOM dom = new EntitySearchFilterDOM(); entitySearchFilters = dom.getFilters(contentType, showletParam,this.getContentManager(), langCode); } else { entitySearchFilters = new EntitySearchFilter[0]; } return entitySearchFilters; } @Override public SyndFeed getSyndFeed(Channel channel, String lang, String feedLink, HttpServletRequest req, HttpServletResponse resp) throws ApsSystemException { SyndFeed feed = null; if (null == feed) { feed = new SyndFeedImpl(); feed.setFeedType(channel.getFeedType()); feed.setTitle(channel.getTitle()); feed.setLink(feedLink); feed.setDescription(channel.getDescription()); List<String> contentsId = this.getContentsId(channel, lang); feed.setEntries(this.getEntries(contentsId, lang, feedLink, req, resp)); } return feed; } private List<SyndEntry> getEntries(List<String> contentsId, String lang, String feedLink, HttpServletRequest req, HttpServletResponse resp) throws ApsSystemException { List<SyndEntry> entries = new ArrayList<SyndEntry>(); Iterator<String> idIterator = contentsId.iterator(); while (idIterator.hasNext()) { String id = (String) idIterator.next(); ContentRecordVO currentContent = this.getContentManager().loadContentVO(id); RssContentMapping mapping = (RssContentMapping) this.getContentMapping().get(currentContent.getTypeCode()); if (null == mapping) { ApsSystemUtils.getLogger().error("Null content mapping by existed channel for content type " + currentContent.getTypeCode()); continue; } entries.add(this.createEntry(currentContent, lang, feedLink, req, resp)); } return entries; } private SyndEntry createEntry(ContentRecordVO contentVO, String langCode, String feedLink, HttpServletRequest req, HttpServletResponse resp) throws ApsSystemException { SyndEntry entry = new SyndEntryImpl(); RssContentMapping mapping = this.getContentMapping().get(contentVO.getTypeCode()); try { Content content = (Content) this.getContentManager().loadContent(contentVO.getId(), true); ITextAttribute titleAttr = (ITextAttribute) content.getAttribute(mapping.getTitleAttributeName()); String title = (titleAttr.getTextForLang(langCode)); if (null == title || title.trim().length() == 0) { title = titleAttr.getText(); } entry.setTitle(title); String link = this.createLink(content, feedLink); entry.setLink(link); entry.setPublishedDate(contentVO.getModify()); ITextAttribute descrAttr = (ITextAttribute) content.getAttribute(mapping.getDescriptionAttributeName()); if (null != descrAttr) { SyndContent description = new SyndContentImpl(); description.setType(JpRssSystemConstants.SYNDCONTENT_TYPE_TEXTHTML); String inLang = descrAttr.getTextForLang(langCode); //TODO Ottimizzare! RequestContext requestContext = new RequestContext(); requestContext.setRequest(req); requestContext.setResponse(resp); if (null != inLang && inLang.length() >0) { String textValue = this.getLinkResolver().resolveLinks(inLang, requestContext); if (null != textValue && textValue.trim().length()>0) { description.setValue(textValue); } else { description.setValue(descrAttr.getText()); } } else { String textValue = this.getLinkResolver().resolveLinks(descrAttr.getText(), requestContext); description.setValue(textValue); } entry.setDescription(description); } } catch (Throwable t) { ApsSystemUtils.logThrowable(t, this, "createEntry"); throw new ApsSystemException("Error in createEntry", t); } return entry; } private String createLink(Content content, String feedLink) { SymbolicLink symbolicLink = new SymbolicLink(); StringBuilder destination = new StringBuilder(feedLink); String viewPage = content.getViewPage(); if (null == viewPage || null == this.getPageManager().getPage(viewPage)) { viewPage = this.getPageManager().getRoot().getCode(); } destination.append(viewPage).append(".page").append("?contentId=").append(content.getId()); symbolicLink.setDestinationToUrl(destination.toString()); return symbolicLink.getUrlDest(); } @SuppressWarnings("unchecked") @Override public Map<String, String> getAvailableContentTypes() { Map<String, String> availableContentTypes = new HashMap<String, String>(); Iterator it = this.getContentMapping().entrySet().iterator(); Map<String, SmallContentType> contentTypes = this.getContentManager().getSmallContentTypesMap(); while (it.hasNext()) { Map.Entry pairs = (Map.Entry)it.next(); String typeCode = (String) pairs.getKey(); SmallContentType smallContentType = (SmallContentType) contentTypes.get(typeCode); if (null != smallContentType) { availableContentTypes.put(typeCode, smallContentType.getDescr()); } } return availableContentTypes; } @Override public RssContentMapping getContentMapping(String typeCode) { RssContentMapping mapping = this.getContentMapping().get(typeCode); if (null != mapping) { return mapping.clone(); } return null; } protected EntitySearchFilter[] addFilter(EntitySearchFilter[] filters, EntitySearchFilter filterToAdd){ int len = filters.length; EntitySearchFilter[] newFilters = new EntitySearchFilter[len + 1]; for(int i=0; i < len; i++){ newFilters[i] = filters[i]; } newFilters[len] = filterToAdd; return newFilters; } private List<String> getContentsId(Channel channel, String langCode) throws ApsSystemException { RssContentMapping mapping = (RssContentMapping) this.getContentMapping().get(channel.getContentType()); if (null == mapping) { ApsSystemUtils.getLogger().error("Null content mapping by existed channel for content type " + channel.getContentType()); return new ArrayList<String>(); } try { EntitySearchFilter[] searchFilters = this.getEntitySearchFilter(channel, langCode);//this.getEntitySearchFilterDOM().getFilters(channel.getContentType(), channel.getFilters()); EntitySearchFilter filterToAdd = new EntitySearchFilter(IContentManager.ENTITY_TYPE_CODE_FILTER_KEY, false, channel.getContentType(), false); EntitySearchFilter[] entitySearchFilters = addFilter(searchFilters, filterToAdd); String[] categories = null; if (null != channel.getCategory() && channel.getCategory().trim().length() > 0) { categories = new String[] {channel.getCategory()}; } Collection<String> userGroupCodes = new ArrayList<String>(); userGroupCodes.add(Group.FREE_GROUP_NAME); List<String> contentsId = this.getContentManager().loadPublicContentsId(channel.getContentType(), categories, entitySearchFilters, userGroupCodes); if (channel.getMaxContentsSize() > 0 && contentsId.size() > channel.getMaxContentsSize()) { return contentsId.subList(0, channel.getMaxContentsSize()); } else { return contentsId; } } catch (Throwable t) { ApsSystemUtils.logThrowable(t, this, "getContentsId"); throw new ApsSystemException("Error in rss contents", t); } } @Override public Map<String, String> getAvailableFeedTypes() { return _availableFeedTypes; } public void setAvailableFeedTypes(Map<String, String> availableFeedTypes) { this._availableFeedTypes = availableFeedTypes; } protected Map<String, RssContentMapping> getContentMapping() { return _contentMapping; } protected void setContentMapping(Map<String, RssContentMapping> contentMapping) { this._contentMapping = contentMapping; } protected ConfigInterface getConfigManager() { return _configManager; } public void setConfigManager(ConfigInterface configManager) { this._configManager = configManager; } protected ILinkResolverManager getLinkResolver() { return _linkResolver; } public void setLinkResolver(ILinkResolverManager linkResolver) { this._linkResolver = linkResolver; } protected IContentManager getContentManager() { return _contentManager; } public void setContentManager(IContentManager contentManager) { this._contentManager = contentManager; } protected IPageManager getPageManager() { return _pageManager; } public void setPageManager(IPageManager pageManager) { this._pageManager = pageManager; } protected IRssDAO getRssDAO() { return _rssDAO; } public void setRssDAO(IRssDAO rssDAO) { this._rssDAO = rssDAO; } protected IKeyGeneratorManager getKeyGeneratorManager() { return _keyGeneratorManager; } public void setKeyGeneratorManager(IKeyGeneratorManager keyGeneratorManager) { this._keyGeneratorManager = keyGeneratorManager; } private Map<String, RssContentMapping> _contentMapping; private IContentManager _contentManager; private IPageManager _pageManager; private ConfigInterface _configManager; private IKeyGeneratorManager _keyGeneratorManager; private Map<String, String> _availableFeedTypes; private ILinkResolverManager _linkResolver; private IRssDAO _rssDAO; }