/*
* File : $Source: /alkacon/cvs/alkacon/com.alkacon.opencms.feeder/src/com/alkacon/opencms/feeder/CmsFeed.java,v $
* Date : $Date: 2008/12/13 13:23:24 $
* Version: $Revision: 1.2 $
*
* This file is part of the Alkacon OpenCms Add-On Module Package
*
* Copyright (c) 2007 Alkacon Software GmbH (http://www.alkacon.com)
*
* The Alkacon OpenCms Add-On Module Package is free software:
* you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alkacon OpenCms Add-On Module Package is distributed
* in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Alkacon OpenCms Add-On Module Package.
* If not, see http://www.gnu.org/licenses/.
*
* For further information about Alkacon Software GmbH, please see the
* company website: http://www.alkacon.com.
*
* For further information about OpenCms, please see the
* project website: http://www.opencms.org.
*/
package com.alkacon.opencms.feeder;
import org.opencms.file.CmsDataAccessException;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsResource;
import org.opencms.file.collectors.I_CmsResourceCollector;
import org.opencms.i18n.CmsLocaleManager;
import org.opencms.main.CmsException;
import org.opencms.main.OpenCms;
import org.opencms.util.CmsStringUtil;
import org.opencms.xml.CmsXmlUtils;
import org.opencms.xml.content.CmsXmlContent;
import org.opencms.xml.content.CmsXmlContentFactory;
import org.opencms.xml.types.I_CmsXmlContentValue;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import com.sun.syndication.feed.synd.SyndImage;
import com.sun.syndication.feed.synd.SyndImageImpl;
import com.sun.syndication.io.FeedException;
/**
* Creates a syndication feed from an XML content that uses the feed schema XSD.<p>
*
* @author Alexander Kandzior
* @author Michael Moossen
*
* @version $Revision: 1.2 $
*/
public class CmsFeed {
/** Node name in the feed XSD. */
public static final String NODE_COLLECTOR = "Collector";
/** Node name in the feed XSD. */
public static final String NODE_COPYRIGHT = "Copyright";
/** Node name in the feed XSD. */
public static final String NODE_DATAFORM = "DataForm";
/** Node name in the feed XSD. */
public static final String NODE_DESCRIPTION = "Description";
/** Node name in the feed XSD. */
public static final String NODE_DESCRIPTIONFORMAT = "DescriptionFormat";
/** Node name in the feed XSD. */
public static final String NODE_ID = "Id";
/** Node name in the feed XSD. */
public static final String NODE_IMAGE = "Image";
/** Node name in the feed XSD. */
public static final String NODE_MAPPING = "Mapping";
/** Node name in the feed XSD. */
public static final String NODE_MAXENTRIES = "MaxEntries";
/** Node name in the feed XSD. */
public static final String NODE_PARAMETER = "Parameter";
/** Node name in the feed XSD. */
public static final String NODE_RESOURCESET = "ResourceSet";
/** Name of the required outer node for the XSD that defines the feed content. */
public static final String NODE_SCHEMA = "AlkaconFeeds";
/** Node name in the feed XSD. */
public static final String NODE_TITLE = "Title";
/** Node name in the feed XSD. */
public static final String NODE_TYPE = "Type";
/** The current users OpenCms context. */
private CmsObject m_cms;
/** The XML content that contains the definition of the feed. */
private CmsXmlContent m_content;
/** The generated feed. */
private CmsFeedGenerator m_feed;
/** The locale to use. */
private Locale m_locale;
/** The resource that defines the Link for the feed. */
private CmsResource m_res;
/** The schema name. */
private String m_schemaName;
/**
* Creates a new, initialized feed based on the current URI of the given OpenCms user context.<p>
*
* The content must use the XSD from the Alkacon feed content definition.<p>
*
* @param cms the current users OpenCms context
*
* @throws CmsException in case something goes wrong
*/
public CmsFeed(CmsObject cms)
throws CmsException {
this(cms, cms.getRequestContext().getUri());
}
/**
* Creates a new feed based on the given resource.<p>
*
* With this constructor, the feed will not be initialized. You must call {@link #init()} first
* before using the feed.<p>
*
* The content must use the XSD from the Alkacon feed content definition.<p>
*
* @param cms the current users OpenCms context
* @param locale the locale to use
* @param res the resource that defines the Link for the feed
*
* @throws CmsException in case something goes wrong
*/
public CmsFeed(CmsObject cms, Locale locale, CmsResource res)
throws CmsException {
this(cms, locale, res, CmsXmlContentFactory.unmarshal(cms, cms.readFile(res)));
}
/**
* Creates a new feed based on the given XML content.<p>
*
* With this constructor, the feed will not be initialized. You must call {@link #init()} first
* before using the feed.<p>
*
* The content must use the XSD from the Alkacon feed content definition.<p>
*
* @param cms the current users OpenCms context
* @param locale the locale to use
* @param res the resource that defines the Link for the feed
* @param content the content to create the feed from
*/
public CmsFeed(CmsObject cms, Locale locale, CmsResource res, CmsXmlContent content) {
m_cms = cms;
m_locale = locale;
m_res = res;
m_content = content;
m_schemaName = m_content.getContentDefinition().getOuterName();
}
/**
* Creates a new, initialized feed from the given resource.<p>
*
* The content must use the XSD from the Alkacon feed content definition.<p>
*
* @param cms the current users OpenCms context
* @param resourceName the resource to create the feed for
*
* @throws CmsException in case something goes wrong
*/
public CmsFeed(CmsObject cms, String resourceName)
throws CmsException {
this(cms, OpenCms.getLocaleManager().getDefaultLocale(cms, resourceName), cms.readResource(resourceName));
init();
}
/**
* Initialize this feed.<p>
*
* @throws CmsException in case something goes wrong
*/
public void init() throws CmsException {
// make sure the schema is of the correct type
if (!NODE_SCHEMA.equals(m_schemaName)) {
throw new CmsException(Messages.get().container(Messages.ERR_BAD_FEED_CD_2, m_schemaName, NODE_SCHEMA));
}
CmsFeedGenerator feed = new CmsFeedGenerator();
processResourceSet(feed, "/"); // this is only for compatibility with v1.x
int resSets = m_content.getValues(NODE_RESOURCESET, m_locale).size();
for (int i = 1; i <= resSets; i++) {
String resSetPath = CmsXmlUtils.createXpath(NODE_RESOURCESET, i);
processResourceSet(feed, resSetPath);
}
// process the feed image (if set / available)
SyndImage image = null;
if (m_content.getValue(NODE_IMAGE, m_locale) != null) {
String basePath = CmsXmlUtils.createXpath(NODE_IMAGE, 1);
String title = m_content.getStringValue(m_cms, CmsXmlUtils.concatXpath(basePath, "Title"), m_locale);
String description = m_content.getStringValue(
m_cms,
CmsXmlUtils.concatXpath(basePath, "Description"),
m_locale);
String url = m_content.getStringValue(m_cms, CmsXmlUtils.concatXpath(basePath, "Url"), m_locale);
String link = m_content.getStringValue(m_cms, CmsXmlUtils.concatXpath(basePath, "Link"), m_locale);
image = new SyndImageImpl();
image.setTitle(title);
image.setDescription(description);
if (CmsStringUtil.isNotEmpty(link)) {
image.setLink(OpenCms.getLinkManager().getServerLink(m_cms, link));
}
if (CmsStringUtil.isNotEmpty(url)) {
image.setUrl(OpenCms.getLinkManager().getServerLink(m_cms, url));
}
}
// calculate the link with full server path
feed.setFeedLink(OpenCms.getLinkManager().getServerLink(m_cms, m_res.getRootPath()));
// calculate the encoding from the properties
String encoding = CmsLocaleManager.getResourceEncoding(m_cms, m_res);
feed.setFeedEncoding(encoding);
// set the remaining variables (null values are handled in the feed generator)
feed.setFeedTitle(m_content.getStringValue(m_cms, NODE_TITLE, m_locale));
feed.setFeedType(m_content.getStringValue(m_cms, NODE_TYPE, m_locale));
feed.setFeedCopyright(m_content.getStringValue(m_cms, NODE_COPYRIGHT, m_locale));
feed.setFeedDescription(m_content.getStringValue(m_cms, NODE_DESCRIPTION, m_locale));
feed.setFeedImage(image);
// now store the created feed internally for later use
m_feed = feed;
}
/**
* Write the feed result to the provided output stream.<p>
*
* @param out the output stream to write the feed to
*
* @throws IOException in case of errors writing to the stream
* @throws FeedException in case of errors generating the feed
* @throws CmsException in case of errors accessing the OpenCms VFS
*/
public void write(OutputStream out) throws IOException, FeedException, CmsException {
m_feed.write(m_cms, m_locale, out);
}
/**
* Write the feed result to the provided writer.<p>
*
* @param writer the writer to write the feed to
*
* @throws IOException in case of errors writing to the stream
* @throws FeedException in case of errors generating the feed
* @throws CmsException in case of errors accessing the OpenCms VFS
*/
public void write(Writer writer) throws IOException, FeedException, CmsException {
m_feed.write(m_cms, m_locale, writer);
}
private void processResourceSet(CmsFeedGenerator feed, String resSetPath)
throws CmsException, CmsDataAccessException {
// first lookup the collector
String collectorStr = m_content.getStringValue(
m_cms,
CmsXmlUtils.concatXpath(resSetPath, NODE_COLLECTOR),
m_locale);
I_CmsResourceCollector collector = OpenCms.getResourceManager().getContentCollector(collectorStr);
if (collector == null) {
throw new CmsException(Messages.get().container(Messages.ERR_BAD_FEED_CD_2, m_schemaName, NODE_SCHEMA));
}
// use the collector to collect the resources for the feed
String params = m_content.getStringValue(m_cms, CmsXmlUtils.concatXpath(resSetPath, NODE_PARAMETER), m_locale);
List entries = collector.getResults(m_cms, collectorStr, params);
// description format
String descFormat = m_content.getStringValue(
m_cms,
CmsXmlUtils.concatXpath(resSetPath, NODE_DESCRIPTIONFORMAT),
m_locale);
// data form parameters
String dataPath = CmsXmlUtils.concatXpath(resSetPath, NODE_DATAFORM);
String dataType = m_content.getStringValue(m_cms, CmsXmlUtils.concatXpath(dataPath, NODE_ID), m_locale);
String maxEntriesVal = m_content.getStringValue(
m_cms,
CmsXmlUtils.concatXpath(dataPath, NODE_MAXENTRIES),
m_locale);
int maxEntries = -1;
if (maxEntriesVal != null) {
try {
maxEntries = Integer.parseInt(maxEntriesVal);
} catch (NumberFormatException e) {
// parsing problem, use default
}
}
// process the default mappings (if set / available)
CmsFeedContentMapping defaultMapping = null;
int mapsize = m_content.getValues(CmsXmlUtils.concatXpath(resSetPath, NODE_MAPPING), m_locale).size();
if (mapsize > 1) {
defaultMapping = new CmsFeedContentMapping(descFormat, dataType, maxEntries);
for (int j = 1; j <= mapsize; j++) {
String basePath = CmsXmlUtils.concatXpath(resSetPath, CmsXmlUtils.createXpath(NODE_MAPPING, j));
String field = m_content.getStringValue(m_cms, CmsXmlUtils.concatXpath(basePath, "Field"), m_locale);
String defaultValue = m_content.getStringValue(
m_cms,
CmsXmlUtils.concatXpath(basePath, "Default"),
m_locale);
String maxLenghtStr = m_content.getStringValue(
m_cms,
CmsXmlUtils.concatXpath(basePath, "MaxLength"),
m_locale);
List xmlNodes = m_content.getValues(CmsXmlUtils.concatXpath(basePath, "XmlNode"), m_locale);
List nodes = new ArrayList(xmlNodes.size());
for (int k = 0; k < xmlNodes.size(); k++) {
nodes.add(((I_CmsXmlContentValue)xmlNodes.get(k)).getStringValue(m_cms));
}
defaultMapping.addFeedFieldMapping(nodes, field, maxLenghtStr, defaultValue);
}
}
feed.addResourceSet(entries, defaultMapping);
}
}