/*
* Copyright (C) 2013 Jens Pelzetter
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.arsdigita.cms;
import com.arsdigita.xml.XML;
import java.math.BigDecimal;
import org.apache.log4j.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
/**
* This is a helper tool for loading data for the RelationAttributes (Database
* Driven Enums) into the database in a loader of a module. This helper class
* uses a XML format for loading the enum data, which looks like this:
*
*
* <ddenums>
* <ddenum name="...">
* <entry key="..." lang="..." id="...">
* <value>...</value>
* <description>...</description>
* <entry>
* </ddenum>
* </ddenums>
*
*
* The root element is {@code } which can appear only once per file.
* The {@code } elements as child
* elements. The {@code element has one attribute, {@code name} which
* contains the name of the enumeration. Each {@code } may have multiple
* {@code} child elements. The {@code } element has three attributes.
*
*
* - {@code key}
- The key of the entry. This attribute is mandatory.
* - {@code lang}
- The language of the entry. This attribute is
* mandatory. The combination of {@code key}
* and {@code lang} should be unique.
* - {@code id}
- This attribute is optional and contains the
* database id of the entry if necessary. The
* value is maybe ignored by this import tool.
*
*
* Each entry has at least a {@code } element as child. The {@code }
* element contains the value of the enum entry. Optionally there can also be
* an description element containing a description of the entry.
*
* @author Jens Pelzetter
* @version $Id$
*/
public class RelationAttributeImportTool {
/** Internal logger instance to faciliate debugging. Enable logging output
* by editing /WEB-INF/conf/log4j.properties int hte runtime environment
* and set com.arsdigita.cms.RelationAttributeImportTool=DEBUG
* by uncommenting or adding the line. */
private final static Logger LOGGER = Logger.getLogger(RelationAttributeImportTool.class);
public void loadData(final String fileName) {
XML.parseResource(fileName, new RelationAttributeXmlHandler());
}
//Suppressing this warnings because they are false positives here.
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.AvoidStringBufferField"})
private class RelationAttributeXmlHandler extends DefaultHandler {
private String currentEnum;
private String currentKey;
private String currentLang;
private String currentId;
private String currentValue;
private String currentDesc;
private StringBuffer charBuffer;
public RelationAttributeXmlHandler() {
super();
//Nothing
}
@Override
public void startElement(final String uri,
final String localName,
final String qName,
final Attributes attributes) {
if ("ddenum".equals(qName)) {
currentEnum = attributes.getValue("name");
} else if ("entry".equals(qName)) {
currentKey = attributes.getValue("key");
currentLang = attributes.getValue("lang");
currentId = attributes.getValue("id");
} else if ("value".equals(qName)) {
//Create new StringBuffer of creating a string from the content of the element
charBuffer = new StringBuffer();
} else if ("description".equals(qName)) {
//Create new StringBuffer of creating a string from the content of the element
charBuffer = new StringBuffer();
}
}
@Override
public void endElement(final String uri,
final String localName,
final String qName) {
if ("ddenum".equals(qName)) {
currentEnum = "";
} else if ("entry".equals(qName)) {
createEntry();
currentKey = "";
currentLang = "";
currentId = "";
currentValue = "";
currentDesc = "";
} else if ("value".equals(qName)) {
//Copy the value of the StringBuffer charBuffer to currentValue
currentValue = charBuffer.toString().trim();
charBuffer = new StringBuffer();
} else if ("description".equals(qName)) {
//Copy the value of the StringBuffer charBuffer to currentValue
currentDesc = charBuffer.toString().trim();
charBuffer = new StringBuffer();
}
}
@Override
public void characters(final char[] chars, final int start, final int length) {
if (charBuffer != null) {
for(int i = start; i < start + length; i++) {
charBuffer.append(chars[i]);
}
}
}
//Supressing this warning since there is no better way yet.
@SuppressWarnings("PMD.NPathComplexity")
private void createEntry() {
if ((currentEnum == null) || currentEnum.isEmpty()) {
LOGGER.warn(String.format(
"Value for current enum is empty. Ignorning entry with key '%s' and lang '%s'.",
currentKey,
currentLang));
return;
}
if ((currentKey == null) || currentKey.isEmpty()) {
LOGGER.warn("No key. Ignorning entry");
return;
}
if ((currentLang == null) || currentLang.isEmpty()) {
LOGGER.warn(String.format("No lang for entry with key '%s'. Ignoring entry",
currentKey));
return;
}
LOGGER.warn("Creating RelationAttribute entry with this values:");
LOGGER.warn(String.format("\tcurrentEnum = '%s'", currentEnum));
LOGGER.warn(String.format("\tcurrentKey = '%s'", currentKey));
LOGGER.warn(String.format("\tcurrentLang = '%s'", currentLang));
LOGGER.warn(String.format("\tcurrentValue = '%s'", currentValue));
final RelationAttribute entry = new RelationAttribute();
if ((currentId != null) && !currentId.isEmpty()) {
entry.setID(new BigDecimal(currentId));
}
entry.setAttribute(currentEnum);
entry.setKey(currentKey);
entry.setLanguage(currentLang);
entry.setName(currentValue);
if ((currentDesc != null) && !currentValue.isEmpty()) {
entry.setDescription(currentDesc);
}
entry.save();
}
}
}