com.gst.mix.service.XBRLBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.gst.mix.service.XBRLBuilder.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.gst.mix.service;

import java.math.BigDecimal;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.gst.mix.data.ContextData;
import com.gst.mix.data.MixTaxonomyData;
import com.gst.mix.data.NamespaceData;
import com.gst.mix.data.XBRLData;
import com.gst.mix.exception.XBRLMappingInvalidException;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class XBRLBuilder {

    private static final String SCHEME_URL = "http://www.themix.org";
    private static final String IDENTIFIER = "000000";
    private static final String UNITID_PURE = "Unit1";
    private static final String UNITID_CUR = "Unit2";

    private Element root;
    private HashMap<ContextData, String> contextMap;
    Date startDate;
    Date endDate;
    private Integer instantScenarioCounter = 1;
    private Integer durationScenarioCounter = 1;

    @Autowired
    private NamespaceReadPlatformService readNamespaceService;

    public String build(final XBRLData xbrlData) {
        return this.build(xbrlData.getResultMap(), xbrlData.getStartDate(), xbrlData.getEndDate(),
                xbrlData.getCurrency());
    }

    public String build(final Map<MixTaxonomyData, BigDecimal> map, final Date startDate, final Date endDate,
            final String currency) {
        this.instantScenarioCounter = 1;
        this.durationScenarioCounter = 1;
        this.contextMap = new HashMap<>();
        final Document doc = DocumentHelper.createDocument();
        this.root = doc.addElement("xbrl");

        this.root.addElement("schemaRef").addNamespace("link",
                "http://www.themix.org/sites/default/files/Taxonomy2010/dct/dc-all_2010-08-31.xsd");

        this.startDate = startDate;
        this.endDate = endDate;

        for (final Entry<MixTaxonomyData, BigDecimal> entry : map.entrySet()) {
            final MixTaxonomyData taxonomy = entry.getKey();
            final BigDecimal value = entry.getValue();
            addTaxonomy(this.root, taxonomy, value);

        }

        addContexts();
        addCurrencyUnit(currency);
        addNumberUnit();

        doc.setXMLEncoding("UTF-8");

        return doc.asXML();
    }

    Element addTaxonomy(final Element rootElement, final MixTaxonomyData taxonomy, final BigDecimal value) {

        // throw an error is start / endate is null
        if (this.startDate == null || this.endDate == null) {
            throw new XBRLMappingInvalidException("start date and end date should not be null");
        }

        final String prefix = taxonomy.getNamespace();
        String qname = taxonomy.getName();
        if (prefix != null && (!prefix.isEmpty())) {
            final NamespaceData ns = this.readNamespaceService.retrieveNamespaceByPrefix(prefix);
            if (ns != null) {

                this.root.addNamespace(prefix, ns.url());
            }
            qname = prefix + ":" + taxonomy.getName();

        }
        final Element xmlElement = rootElement.addElement(qname);

        final String dimension = taxonomy.getDimension();
        final SimpleDateFormat timeFormat = new SimpleDateFormat("MM_dd_yyyy");

        ContextData context = null;
        if (dimension != null) {
            final String[] dims = dimension.split(":");

            if (dims.length == 2) {
                context = new ContextData(dims[0], dims[1], taxonomy.getType());
                if (this.contextMap.containsKey(context)) {

                } else {

                }
            }
        }

        if (context == null) {
            context = new ContextData(null, null, taxonomy.getType());
        }

        if (!this.contextMap.containsKey(context)) {

            final String startDateStr = timeFormat.format(this.startDate);
            final String endDateStr = timeFormat.format(this.endDate);

            final String contextRefID = (context.getPeriodType() == 0)
                    ? ("As_Of_" + endDateStr + (this.instantScenarioCounter++))
                    : ("Duration_" + startDateStr + "_To_" + endDateStr + (this.durationScenarioCounter++));

            this.contextMap.put(context, contextRefID);
        }

        xmlElement.addAttribute("contextRef", this.contextMap.get(context));
        xmlElement.addAttribute("unitRef", getUnitRef(taxonomy));
        xmlElement.addAttribute("decimals", getNumberOfDecimalPlaces(value).toString());

        // add the child
        xmlElement.addText(value.toPlainString());

        return xmlElement;
    }

    private String getUnitRef(final MixTaxonomyData tx) {
        return tx.isPortfolio() ? UNITID_PURE : UNITID_CUR;
    }

    /**
     * Adds the generic number unit
     */
    void addNumberUnit() {
        final Element numerUnit = this.root.addElement("unit");
        numerUnit.addAttribute("id", UNITID_PURE);
        final Element measure = numerUnit.addElement("measure");
        measure.addText("xbrli:pure");

    }

    /**
     * Adds the currency unit to the document
     * 
     * @param currencyCode
     */
    public void addCurrencyUnit(final String currencyCode) {
        final Element currencyUnitElement = this.root.addElement("unit");
        currencyUnitElement.addAttribute("id", UNITID_CUR);
        final Element measure = currencyUnitElement.addElement("measure");
        measure.addText("iso4217:" + currencyCode);

    }

    public void addContexts() {
        final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        for (final Entry<ContextData, String> entry : this.contextMap.entrySet()) {
            final ContextData context = entry.getKey();
            final Element contextElement = this.root.addElement("context");
            contextElement.addAttribute("id", entry.getValue());
            contextElement.addElement("entity").addElement("identifier").addAttribute("scheme", SCHEME_URL)
                    .addText(IDENTIFIER);

            final Element periodElement = contextElement.addElement("period");

            if (context.getPeriodType() == 0) {
                periodElement.addElement("instant").addText(format.format(this.endDate));
            } else {
                periodElement.addElement("startDate").addText(format.format(this.startDate));
                periodElement.addElement("endDate").addText(format.format(this.endDate));
            }

            final String dimension = context.getDimension();
            final String dimType = context.getDimensionType();
            if (dimType != null && dimension != null) {
                contextElement.addElement("scenario").addElement("explicitMember")
                        .addAttribute("dimension", dimType).addText(dimension);
            }
        }

    }

    private Integer getNumberOfDecimalPlaces(final BigDecimal bigDecimal) {
        final String string = bigDecimal.stripTrailingZeros().toPlainString();
        final int index = string.indexOf(".");
        return index < 0 ? 0 : string.length() - index - 1;
    }
}