/*
* File : $Source: /alkacon/cvs/alkacon/com.alkacon.opencms.feeder/src/com/alkacon/opencms/feeder/CmsFeedXmlContentHandler.java,v $
* Date : $Date: 2007/12/13 15:48:47 $
* Version: $Revision: 1.1 $
*
* 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.configuration.CmsConfigurationManager;
import org.opencms.i18n.CmsEncoder;
import org.opencms.main.CmsRuntimeException;
import org.opencms.util.CmsFileUtil;
import org.opencms.xml.CmsXmlContentDefinition;
import org.opencms.xml.CmsXmlEntityResolver;
import org.opencms.xml.CmsXmlException;
import org.opencms.xml.CmsXmlUtils;
import org.opencms.xml.content.CmsDefaultXmlContentHandler;
import org.opencms.xml.content.Messages;
import org.opencms.xml.types.I_CmsXmlSchemaType;
import java.util.Collections;
import java.util.Iterator;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
/**
* Adds syndication feed mapping rules to the default XML content handler.<p>
*
* @author Alexander Kandzior
*
* @version $Revision: 1.1 $
*/
public class CmsFeedXmlContentHandler extends CmsDefaultXmlContentHandler {
/** Constant for the "feedrule" element name. */
public static final String APPINFO_FEEDRULE = "feedrule";
/** Constant for the "feedrules" element name. */
public static final String APPINFO_FEEDRULES = "feedrules";
/** Constant for the "default" attribute. */
public static final String ATTR_DEFAULT = "default";
/** Constant for the "maxLength" attribute. */
public static final String ATTR_MAXLENGTH = "maxLength";
/** The path to the Alkacon OpenCms Feeder package (calculated from the package name). */
public static final String FEED_PACKAGE_PATH = CmsFeed.class.getPackage().getName().replace('.', '/');
/** The file where the extended feed schema is located. */
public static final String FEED_APPINFO_SCHEMA_FILE = FEED_PACKAGE_PATH + "/FeedAppinfo.xsd";
/** The XML system id for the extended feed schema. */
public static final String FEED_APPINFO_SCHEMA_SYSTEM_ID = CmsConfigurationManager.DEFAULT_DTD_PREFIX
+ FEED_APPINFO_SCHEMA_FILE;
/** The feed mapping this class is all about. */
protected CmsFeedContentMapping m_feedMapping;
/**
* Static initializer for caching the extended feed validation schema.<p>
*/
static {
// the schema definition is located in a separate file for easier editing
byte[] appinfoSchema;
try {
appinfoSchema = CmsFileUtil.readFile(FEED_APPINFO_SCHEMA_FILE);
} catch (Exception e) {
throw new CmsRuntimeException(Messages.get().container(
org.opencms.xml.types.Messages.ERR_XMLCONTENT_LOAD_SCHEMA_1,
FEED_APPINFO_SCHEMA_FILE), e);
}
CmsXmlEntityResolver.cacheSystemId(FEED_APPINFO_SCHEMA_SYSTEM_ID, appinfoSchema);
}
/**
* Returns the initialized feed mapping for this XML content handler.<p>
*
* @return the initialized feed mapping for this XML content handler
*/
public CmsFeedContentMapping getFeedMapping() {
return m_feedMapping;
}
/**
* @see org.opencms.xml.content.CmsDefaultXmlContentHandler#initialize(org.dom4j.Element, org.opencms.xml.CmsXmlContentDefinition)
*/
public synchronized void initialize(Element appInfoElement, CmsXmlContentDefinition contentDefinition)
throws CmsXmlException {
if (appInfoElement != null) {
// first initialize all the default values
super.initialize(appInfoElement, contentDefinition);
Element feedElement = appInfoElement.element(APPINFO_FEEDRULES);
if (feedElement != null) {
initFeedRules(feedElement, contentDefinition);
}
}
}
/**
* Adds a feed rule mapping.<p>
*
* @param contentDefinition the XML content definition this XML content handler belongs to
* @param xmlField the element name to map to the feed
* @param feedField the feed field to map the XML field to
* @param maxLength the optional max length of the field
* @param defaultValue the optional default value for the mapping
*
* @throws CmsXmlException in case an unknown element name is used
*/
protected void addFeedRule(
CmsXmlContentDefinition contentDefinition,
String xmlField,
String feedField,
String maxLength,
String defaultValue) throws CmsXmlException {
if (contentDefinition.getSchemaType(xmlField) == null) {
throw new CmsXmlException(
Messages.get().container(Messages.ERR_XMLCONTENT_INVALID_ELEM_MAPPING_1, xmlField));
}
m_feedMapping.addFeedFieldMapping(
Collections.singletonList(CmsXmlUtils.createXpath(xmlField, 1)),
feedField,
maxLength,
defaultValue);
}
/**
* @see org.opencms.xml.content.CmsDefaultXmlContentHandler#init()
*/
protected void init() {
super.init();
m_feedMapping = new CmsFeedContentMapping();
}
/**
* Initializes the feed rule mappings for this content handler.<p>
*
* @param root the "feedrules" element from the appinfo node of the XML content definition
* @param contentDefinition the content definition the mappings belong to
*
* @throws CmsXmlException if something goes wrong
*/
protected void initFeedRules(Element root, CmsXmlContentDefinition contentDefinition) throws CmsXmlException {
Iterator i = root.elementIterator(APPINFO_FEEDRULE);
while (i.hasNext()) {
// iterate all "mapping" elements in the "mappings" node
Element element = (Element)i.next();
// this is a mapping node
String xmlField = element.attributeValue(APPINFO_ATTR_ELEMENT);
String maptoName = element.attributeValue(APPINFO_ATTR_MAPTO);
String maxLength = element.attributeValue(ATTR_MAXLENGTH);
String defaultValue = element.attributeValue(ATTR_DEFAULT);
if ((xmlField != null) && (maptoName != null)) {
// add the element mapping
addFeedRule(contentDefinition, xmlField, maptoName, maxLength, defaultValue);
}
}
}
/**
* @see org.opencms.xml.content.CmsDefaultXmlContentHandler#validateAppinfoElement(org.dom4j.Element)
*/
protected void validateAppinfoElement(Element appinfoElement) throws CmsXmlException {
// create a document to validate
Document doc = DocumentHelper.createDocument();
Element root = doc.addElement(APPINFO_APPINFO);
// attach the default appinfo schema
root.add(I_CmsXmlSchemaType.XSI_NAMESPACE);
root.addAttribute(I_CmsXmlSchemaType.XSI_NAMESPACE_ATTRIBUTE_NO_SCHEMA_LOCATION, FEED_APPINFO_SCHEMA_SYSTEM_ID);
// append the content from the appinfo node in the content definition
root.appendContent(appinfoElement);
// now validate the document with the default appinfo schema
CmsXmlUtils.validateXmlStructure(doc, CmsEncoder.ENCODING_UTF_8, new CmsXmlEntityResolver(null));
}
}