IBaseDataObjectXmlHelper.java
package emissary.core;
import emissary.core.IBaseDataObjectXmlCodecs.ElementDecoders;
import emissary.core.IBaseDataObjectXmlCodecs.ElementEncoders;
import emissary.core.channels.SeekableByteChannelFactory;
import emissary.kff.KffDataObjectHandler;
import emissary.util.xml.AbstractJDOMUtil;
import org.apache.commons.lang3.Validate;
import org.jdom2.Document;
import org.jdom2.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import static emissary.core.constants.IbdoXmlElementNames.ANSWERS;
import static emissary.core.constants.IbdoXmlElementNames.ATTACHMENT_ELEMENT_PREFIX;
import static emissary.core.constants.IbdoXmlElementNames.BIRTH_ORDER;
import static emissary.core.constants.IbdoXmlElementNames.BROKEN;
import static emissary.core.constants.IbdoXmlElementNames.CLASSIFICATION;
import static emissary.core.constants.IbdoXmlElementNames.CURRENT_FORM;
import static emissary.core.constants.IbdoXmlElementNames.DATA;
import static emissary.core.constants.IbdoXmlElementNames.EXTRACTED_RECORD_ELEMENT_PREFIX;
import static emissary.core.constants.IbdoXmlElementNames.FILENAME;
import static emissary.core.constants.IbdoXmlElementNames.FONT_ENCODING;
import static emissary.core.constants.IbdoXmlElementNames.FOOTER;
import static emissary.core.constants.IbdoXmlElementNames.HEADER;
import static emissary.core.constants.IbdoXmlElementNames.HEADER_ENCODING;
import static emissary.core.constants.IbdoXmlElementNames.ID;
import static emissary.core.constants.IbdoXmlElementNames.NUM_CHILDREN;
import static emissary.core.constants.IbdoXmlElementNames.NUM_SIBLINGS;
import static emissary.core.constants.IbdoXmlElementNames.OUTPUTABLE;
import static emissary.core.constants.IbdoXmlElementNames.PARAMETER;
import static emissary.core.constants.IbdoXmlElementNames.PRIORITY;
import static emissary.core.constants.IbdoXmlElementNames.PROCESSING_ERROR;
import static emissary.core.constants.IbdoXmlElementNames.RESULT;
import static emissary.core.constants.IbdoXmlElementNames.SETUP;
import static emissary.core.constants.IbdoXmlElementNames.TRANSACTION_ID;
import static emissary.core.constants.IbdoXmlElementNames.VIEW;
import static emissary.core.constants.IbdoXmlElementNames.WORK_BUNDLE_ID;
/**
* This class helps convert IBaseDataObjects to and from XML.
*/
public final class IBaseDataObjectXmlHelper {
/**
* Logger instance
*/
private static final Logger LOGGER = LoggerFactory.getLogger(IBaseDataObjectXmlHelper.class);
private IBaseDataObjectXmlHelper() {}
/**
* Setup a typical BDO
*
* @param sbcf initial channel factory for the data
* @param classification initial classification string
* @param formAndFileType initial form and file type
* @param kff an existing Kff handler
* @return a typical BDO with the specified data
*/
public static IBaseDataObject createStandardInitialIbdo(final IBaseDataObject ibdo, final SeekableByteChannelFactory sbcf,
final String classification, final String formAndFileType, final KffDataObjectHandler kff) {
final IBaseDataObject tempIbdo = DataObjectFactory.getInstance();
// We want to return the ibdo with the data field equal to null. This can only
// be accomplished if the data is never set. Therefore, we have to set the data
// on a separate ibdo, hash the ibdo and then transfer just the parameters back
// to the original ibdo.
tempIbdo.setChannelFactory(sbcf);
kff.hash(tempIbdo);
ibdo.setParameters(tempIbdo.getParameters());
ibdo.setCurrentForm(formAndFileType);
ibdo.setFileType(formAndFileType);
ibdo.setClassification(classification);
return ibdo;
}
/**
* Creates an IBaseDataObject and associated children from an XML document.
*
* @param document containing the IBaseDataObject and children descriptions.
* @param children the list where the children will be added.
* @param decoders used to decode XML into ibdo.
* @return the IBaseDataObject.
*/
public static IBaseDataObject ibdoFromXml(final Document document, final List<IBaseDataObject> children, final ElementDecoders decoders) {
Validate.notNull(document, "Required document != null!");
Validate.notNull(children, "Required children != null!");
Validate.notNull(decoders, "Required: decoders not null!");
final Element root = document.getRootElement();
final Element answersElement = root.getChild(ANSWERS);
final IBaseDataObject parentIbdo = DataObjectFactory.getInstance();
final List<Element> answerChildren = answersElement.getChildren();
ibdoFromXmlMainElements(answersElement, parentIbdo, decoders);
for (final Element answerChild : answerChildren) {
final IBaseDataObject childIbdo = DataObjectFactory.getInstance();
final String childName = answerChild.getName();
if (childName.startsWith(EXTRACTED_RECORD_ELEMENT_PREFIX)) {
parentIbdo.addExtractedRecord(ibdoFromXmlMainElements(answerChild, childIbdo, decoders));
} else if (childName.startsWith(ATTACHMENT_ELEMENT_PREFIX)) {
children.add(ibdoFromXmlMainElements(answerChild, childIbdo, decoders));
}
}
return parentIbdo;
}
/**
* Creates an IBaseDataObject from an XML element excluding Extracted Records and children.
*
* @param element to create IBaseDataObject from.
* @param ibdo to apply the element values to.
* @param decoders used to decode XML into ibdo.
* @return the IBaseDataObject that was passed in.
*/
public static IBaseDataObject ibdoFromXmlMainElements(final Element element, final IBaseDataObject ibdo,
final ElementDecoders decoders) {
Validate.notNull(element, "Required: element not null!");
Validate.notNull(ibdo, "Required: ibdo not null!");
Validate.notNull(decoders, "Required: decoders not null!");
try {
decoders.decodeInteger(element, ibdo, BIRTH_ORDER);
decoders.decodeString(element, ibdo, BROKEN);
decoders.decodeString(element, ibdo, CLASSIFICATION);
decoders.decodeString(element, ibdo, CURRENT_FORM);
decoders.decodeSeekableByteChannelFactory(element, ibdo, DATA);
decoders.decodeString(element, ibdo, FILENAME);
decoders.decodeString(element, ibdo, FONT_ENCODING);
decoders.decodeByteArray(element, ibdo, FOOTER);
decoders.decodeByteArray(element, ibdo, HEADER);
decoders.decodeString(element, ibdo, HEADER_ENCODING);
decoders.decodeString(element, ibdo, ID);
decoders.decodeInteger(element, ibdo, NUM_CHILDREN);
decoders.decodeInteger(element, ibdo, NUM_SIBLINGS);
decoders.decodeBoolean(element, ibdo, OUTPUTABLE);
decoders.decodeStringObject(element, ibdo, PARAMETER);
decoders.decodeInteger(element, ibdo, PRIORITY);
decoders.decodeString(element, ibdo, PROCESSING_ERROR);
decoders.decodeString(element, ibdo, TRANSACTION_ID);
decoders.decodeStringByteArray(element, ibdo, VIEW);
decoders.decodeString(element, ibdo, WORK_BUNDLE_ID);
} catch (IOException e) {
LOGGER.error("Failed to parse XML!", e);
}
return ibdo;
}
/**
* Creates an XML Element from a parent IBaseDataObject and a list of children IBaseDataObjects.
*
* @param parent the parent IBaseDataObject
* @param children the children IBaseDataObjects.
* @param initialIbdo the initial IBaseDataObject.
* @param encoders used to encode ibdo into XML.
* @return the XML Element.
*/
public static Element xmlElementFromIbdo(final IBaseDataObject parent, final List<IBaseDataObject> children,
final IBaseDataObject initialIbdo, final ElementEncoders encoders) {
Validate.notNull(parent, "Required: parent != null!");
Validate.notNull(children, "Required: children != null!");
Validate.notNull(initialIbdo, "Required: initialIbdo != null!");
Validate.notNull(encoders, "Required: encoders not null!");
final Element rootElement = new Element(RESULT);
final Element setupElement = new Element(SETUP);
rootElement.addContent(setupElement);
xmlFromIbdoMainElements(initialIbdo, setupElement, encoders);
final Element answersElement = new Element(ANSWERS);
rootElement.addContent(answersElement);
xmlFromIbdoMainElements(parent, answersElement, encoders);
final List<IBaseDataObject> extractedRecords = parent.getExtractedRecords();
if (extractedRecords != null) {
for (int i = 0; i < extractedRecords.size(); i++) {
final IBaseDataObject extractedRecord = extractedRecords.get(i);
final Element extractElement = new Element(EXTRACTED_RECORD_ELEMENT_PREFIX + (i + 1));
xmlFromIbdoMainElements(extractedRecord, extractElement, encoders);
answersElement.addContent(extractElement);
}
}
for (int i = 0; i < children.size(); i++) {
final IBaseDataObject child = children.get(i);
final Element childElement = new Element(ATTACHMENT_ELEMENT_PREFIX + (i + 1));
xmlFromIbdoMainElements(child, childElement, encoders);
answersElement.addContent(childElement);
}
return rootElement;
}
/**
* Creates an XML string from a parent IBaseDataObject and a list of children IBaseDataObjects.
*
* @param parent the parent IBaseDataObject
* @param children the children IBaseDataObjects.
* @param initialIbdo the initial IBaseDataObject.
* @param encoders used to encode ibdo into XML.
* @return the XML string.
*/
public static String xmlFromIbdo(final IBaseDataObject parent, final List<IBaseDataObject> children,
final IBaseDataObject initialIbdo, final ElementEncoders encoders) {
final Element rootElement = xmlElementFromIbdo(parent, children, initialIbdo, encoders);
return AbstractJDOMUtil.toString(new Document(rootElement));
}
/**
* Creates xml from the IBaseDataObject excluding the extracted records and children.
*
* @param ibdo to create xml from.
* @param element to add the xml to.
* @param encoders used to encode ibdo into XML.
*/
public static void xmlFromIbdoMainElements(final IBaseDataObject ibdo, final Element element, final ElementEncoders encoders) {
Validate.notNull(ibdo, "Required: ibdo not null!");
Validate.notNull(element, "Required: element not null!");
Validate.notNull(encoders, "Required: encoders not null!");
encoders.seekableByteChannelFactoryEncoder.encode(Collections.singletonList(ibdo.getChannelFactory()), element, DATA);
encoders.integerEncoder.encode(Collections.singletonList(ibdo.getBirthOrder()), element, BIRTH_ORDER);
encoders.stringEncoder.encode(Collections.singletonList(ibdo.getBroken()), element, BROKEN);
encoders.stringEncoder.encode(Collections.singletonList(ibdo.getClassification()), element, CLASSIFICATION);
encoders.stringEncoder.encode(ibdo.getAllCurrentForms(), element, CURRENT_FORM);
encoders.stringEncoder.encode(Collections.singletonList(ibdo.getFilename()), element, FILENAME);
encoders.stringEncoder.encode(Collections.singletonList(ibdo.getFontEncoding()), element, FONT_ENCODING);
encoders.byteArrayEncoder.encode(Collections.singletonList(ibdo.footer()), element, FOOTER);
encoders.byteArrayEncoder.encode(Collections.singletonList(ibdo.header()), element, HEADER);
encoders.stringEncoder.encode(Collections.singletonList(ibdo.getHeaderEncoding()), element, HEADER_ENCODING);
encoders.stringEncoder.encode(Collections.singletonList(ibdo.getId()), element, ID);
encoders.integerEncoder.encode(Collections.singletonList(ibdo.getNumChildren()), element, NUM_CHILDREN);
encoders.integerEncoder.encode(Collections.singletonList(ibdo.getNumSiblings()), element, NUM_SIBLINGS);
encoders.booleanEncoder.encode(Collections.singletonList(ibdo.isOutputable()), element, OUTPUTABLE);
encoders.integerEncoder.encode(Collections.singletonList(ibdo.getPriority()), element, PRIORITY);
encoders.stringEncoder.encode(Collections.singletonList(ibdo.getProcessingError()), element, PROCESSING_ERROR);
encoders.stringEncoder.encode(Collections.singletonList(ibdo.getTransactionId()), element, TRANSACTION_ID);
encoders.stringEncoder.encode(Collections.singletonList(ibdo.getWorkBundleId()), element, WORK_BUNDLE_ID);
encoders.stringObjectEncoder.encode(Collections.singletonList(ibdo.getParameters()), element, PARAMETER);
encoders.stringByteArrayEncoder.encode(Collections.singletonList(ibdo.getAlternateViews()), element, VIEW);
}
}