net.sf.cb2xml.convert.MainframeToXml.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.cb2xml.convert.MainframeToXml.java

Source

/*************************************************************
 * This file is part of CB2XML.  
 * See the file "LICENSE" for copyright information and the
 * terms and conditions for copying, distribution and
 * modification of CB2XML.
 *************************************************************
 */

package net.sf.cb2xml.convert;

import net.sf.cb2xml.util.XmlUtils;
import org.apache.commons.lang.StringUtils;
import org.jcopybook.JCopybookUnmarshallException;
import org.jcopybook.SignedNumericMappingTable;
import org.jcopybook.Utils;
import org.w3c.dom.*;

import java.io.BufferedReader;
import java.io.Reader;
import java.io.StringReader;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;

/**
 * routines to convert a copybook equivalent mainframe buffer into its XML form
 * given the XML form of the copybook
 * to-do: all the stuff related to COMP fields, packed decimal amd all other non-straightforward field types
 * <p/>
 * * note that files within the "net.sf.cb2xml.convert" package are not stable
 *
 * @author Peter Thomas, Artem Andreenko, Bijaya Kumar Pradhan
 */

public class MainframeToXml {

    private String mainframeBuffer = null;
    private Document resultDocument = null;
    private Map<String, BigInteger> numerics = new HashMap<String, BigInteger>();
    //private int globalOffset;

    private static String stripNullChars(String in) {
        try {
            Reader reader = new BufferedReader(new StringReader(in));
            StringBuffer buffer = new StringBuffer();
            int ch;
            while ((ch = reader.read()) > -1) {
                if (ch != 0) {
                    buffer.append((char) ch);
                } else {
                    buffer.append(' ');
                }
            }
            reader.close();
            return buffer.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public Document convert(String mainframeBuffer, Document copyBookXml) throws JCopybookUnmarshallException {
        this.resultDocument = XmlUtils.getNewXmlDocument();
        try {
            this.mainframeBuffer = stripNullChars(mainframeBuffer);
            int bufferLength = mainframeBuffer.length();
            Element documentElement = copyBookXml.getDocumentElement();

            Element recordNode = Utils.getFirstElement(documentElement);
            Element resultRoot = resultDocument.createElement(documentElement.getTagName());
            int recordLength = Integer.parseInt(recordNode.getAttribute("display-length"));

            for (int offset = 0; offset < bufferLength; offset += recordLength) {
                if ("true".equals(recordNode.getAttribute("redefined")))
                    continue;
                Element resultTree = convertNode(recordNode, new Context());
                resultRoot.appendChild(resultTree);
            }
            resultDocument.appendChild(resultRoot);
            return resultDocument;
        } catch (Exception e) {
            if (e instanceof JCopybookUnmarshallException)
                throw (JCopybookUnmarshallException) e;
            throw new JCopybookUnmarshallException("can't unmarshall copybook", e, mainframeBuffer,
                    XmlUtils.domToString(resultDocument).toString(), null, null, copyBookXml);
        }
    }

    private class Context {
        public int offset;
    }

    private Element convertNode(Element element, Context context) throws JCopybookUnmarshallException {
        String text = null;
        String resultElementName = element.getAttribute("name").replaceAll("[^0-9^A-Z\\-]+", "||");
        Element resultElement = resultDocument.createElement(resultElementName);
        try {
            int length = Integer.parseInt(element.getAttribute("display-length"));
            int childElementCount = 0;
            NodeList nodeList = element.getChildNodes();
            for (int i = 0; i < nodeList.getLength(); i++) {
                Node node = nodeList.item(i);
                if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
                    Element childElement = (Element) node;
                    if (!childElement.getAttribute("level").equals("88")
                            && "item".equals(childElement.getNodeName())) {
                        childElementCount++;
                        if (childElement.hasAttribute("occurs")) {
                            boolean dependOn = StringUtils.isNotEmpty(childElement.getAttribute("depending-on"));
                            BigInteger count = numerics.get(childElement.getAttribute("depending-on"));
                            int childOccurs = Integer.parseInt(childElement.getAttribute("occurs"));
                            if (dependOn && count != null) {
                                childOccurs = count.intValue();
                            }
                            for (int j = 0; j < childOccurs; j++) {
                                resultElement.appendChild(convertNode(childElement, context));
                            }
                        } else {
                            if (!"item".equals(childElement.getAttribute("name")))
                                resultElement.appendChild(convertNode(childElement, context));
                        }
                    }
                }
            }
            if (childElementCount == 0 && !"true".equals(element.getAttribute("redefined"))) {
                text = mainframeBuffer.substring(context.offset, context.offset + length);
                if ("true".equals(element.getAttribute("numeric"))) {
                    String textForNumeric = text.trim();
                    if (textForNumeric.isEmpty()) {
                        textForNumeric = "true".equals(element.getAttribute("signed")) ? "{" : "0";
                    }
                    textForNumeric = removeLeftZeros(textForNumeric);
                    if ("true".equals(element.getAttribute("signed"))) {
                        String originalDigit = textForNumeric.substring(textForNumeric.length() - 1,
                                textForNumeric.length());
                        String digit = SignedNumericMappingTable.decodeMap.get(originalDigit);
                        if (digit == null)
                            throw new Exception("bad signed numeric last digit: " + originalDigit);
                        textForNumeric = (digit.startsWith("-") ? "-" : "")
                                + textForNumeric.substring(0, textForNumeric.length() - 1)
                                + (digit.length() == 2 ? digit.substring(1) : digit);
                    }
                    if (textForNumeric.length() == 0)
                        text = "0";
                    else if (StringUtils.isNotEmpty(element.getAttribute("scale"))) {
                        int scale = Integer.parseInt(element.getAttribute("scale"));
                        textForNumeric = getDecimalValue(textForNumeric, scale);
                    } else
                        numerics.put(resultElementName, new BigInteger(textForNumeric));
                    text = textForNumeric;
                }
                context.offset += length;
                Text textNode = resultDocument.createTextNode(text.trim());
                resultElement.appendChild(textNode);
            }
            return resultElement;
        } catch (Exception e) {
            if (e instanceof JCopybookUnmarshallException)
                throw (JCopybookUnmarshallException) e;
            throw new JCopybookUnmarshallException(
                    String.format("can't parse copybook string on element '%s' and text '%s'", resultElementName,
                            text),
                    e, mainframeBuffer, XmlUtils.domToString(resultElement.getOwnerDocument()).toString(),
                    resultElementName, text, element.getOwnerDocument());
        }
    }

    private String removeLeftZeros(String num) {
        if ("0".equals(num))
            return num;
        int pos = -1;
        while (true) {
            int currentPos = num.indexOf("0", pos + 1);
            if (currentPos - 1 != pos)
                break;
            pos++;
        }
        num = num.substring(pos + 1, num.length());
        if (num.isEmpty())
            num = "0";
        return num;
    }

    private String getDecimalValue(String text, int scale) {
        if (text.length() < scale) {
            StringBuilder buf = new StringBuilder();
            for (int i = 0; i < scale - text.length(); i++) {
                buf.append("0");
            }
            buf.append(text);
            text = buf.toString();
        }
        return String.format("%s.%s", text.substring(0, text.length() - scale),
                text.substring(text.length() - scale));
    }

    private int getElementLength(Node node) {
        if (!"item".equals(node.getNodeName()))
            return 0;
        String attribute = getAttribute(node, "display-length");
        int len = 0;
        if (StringUtils.isNotEmpty(attribute))
            len = Integer.parseInt(attribute);
        String occurs = getAttribute(node, "occurs");

        //for loop we check the childs
        if (StringUtils.isNotEmpty(occurs)) {
            NodeList childs = node.getChildNodes();
            for (int i = 0; i < childs.getLength(); i++) {
                len += getElementLength(childs.item(i));
            }
        }

        return len;
    }

    private String getAttribute(Node node, String attrName) {
        if (node.getAttributes() == null)
            return null;
        Node attr = node.getAttributes().getNamedItem(attrName);
        return attr != null ? attr.getNodeValue() : null;
    }
}