at.peppol.commons.tools.MainCreateCodelistsFilesFromExcel.java Source code

Java tutorial

Introduction

Here is the source code for at.peppol.commons.tools.MainCreateCodelistsFilesFromExcel.java

Source

/**
 * Version: MPL 1.1/EUPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Copyright The PEPPOL project (http://www.peppol.eu)
 *
 * Alternatively, the contents of this file may be used under the
 * terms of the EUPL, Version 1.1 or - as soon they will be approved
 * by the European Commission - subsequent versions of the EUPL
 * (the "Licence"); You may not use this work except in compliance
 * with the Licence.
 * You may obtain a copy of the Licence at:
 * http://joinup.ec.europa.eu/software/page/eupl/licence-eupl
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and
 * limitations under the Licence.
 *
 * If you wish to allow use of your version of this file only
 * under the terms of the EUPL License and not to allow others to use
 * your version of this file under the MPL, indicate your decision by
 * deleting the provisions above and replace them with the notice and
 * other provisions required by the EUPL License. If you do not delete
 * the provisions above, a recipient may use your version of this file
 * under either the MPL or the EUPL License.
 */
package at.peppol.commons.tools;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.oasis.genericode.v10.CodeListDocument;
import org.oasis.genericode.v10.Row;
import org.oasis.genericode.v10.UseType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;

import at.peppol.commons.identifier.CIdentifier;
import at.peppol.commons.identifier.IdentifierUtils;
import at.peppol.commons.identifier.doctype.IPeppolDocumentTypeIdentifierParts;
import at.peppol.commons.identifier.doctype.IPeppolPredefinedDocumentTypeIdentifier;
import at.peppol.commons.identifier.doctype.PeppolDocumentTypeIdentifierParts;
import at.peppol.commons.identifier.doctype.SimpleDocumentTypeIdentifier;
import at.peppol.commons.identifier.issuingagency.IIdentifierIssuingAgency;
import at.peppol.commons.identifier.participant.SimpleParticipantIdentifier;
import at.peppol.commons.identifier.process.IPeppolPredefinedProcessIdentifier;
import at.peppol.commons.identifier.process.SimpleProcessIdentifier;

import com.phloc.commons.annotations.Nonempty;
import com.phloc.commons.annotations.ReturnsMutableCopy;
import com.phloc.commons.charset.CCharset;
import com.phloc.commons.collections.ContainerHelper;
import com.phloc.commons.io.IReadableResource;
import com.phloc.commons.io.file.FileUtils;
import com.phloc.commons.io.file.SimpleFileIO;
import com.phloc.commons.io.resource.FileSystemResource;
import com.phloc.commons.microdom.IMicroDocument;
import com.phloc.commons.microdom.IMicroElement;
import com.phloc.commons.microdom.impl.MicroDocument;
import com.phloc.commons.microdom.serialize.MicroWriter;
import com.phloc.commons.regex.RegExHelper;
import com.phloc.commons.string.StringHelper;
import com.phloc.commons.string.StringParser;
import com.phloc.commons.version.Version;
import com.phloc.commons.xml.serialize.XMLWriter;
import com.phloc.commons.xml.serialize.XMLWriterSettings;
import com.phloc.genericode.Genericode10CodeListMarshaller;
import com.phloc.genericode.Genericode10Utils;
import com.phloc.genericode.excel.ExcelReadOptions;
import com.phloc.genericode.excel.ExcelSheetToCodeList;
import com.sun.codemodel.CodeWriter;
import com.sun.codemodel.JArray;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JEnumConstant;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JInvocation;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JVar;
import com.sun.codemodel.writer.FileCodeWriter;

/**
 * Utility class to create the Genericode files from the Excel code list. Also
 * creates Java source files with the predefined identifiers.
 * 
 * @author PEPPOL.AT, BRZ, Philip Helger
 */
public final class MainCreateCodelistsFilesFromExcel {
    private static final Logger s_aLogger = LoggerFactory.getLogger(MainCreateCodelistsFilesFromExcel.class);
    private static final Version CODELIST_VERSION = new Version(1, 1, 1);
    private static final String EXCEL_FILE = "src/main/codelists/PEPPOL Code Lists 1.1.1.xls";
    private static final String SHEET_PARTICIPANT = "Participant";
    private static final String SHEET_DOCUMENT = "Document";
    private static final String SHEET_PROCESS = "Process";
    private static final String RESULT_DIRECTORY = "src/main/resources/codelists/";
    private static final JCodeModel s_aCodeModel = new JCodeModel();
    private static JDefinedClass s_jEnumPredefinedDoc;

    private static void _writeGenericodeFile(@Nonnull final CodeListDocument aCodeList,
            @Nonnull final String sFilename) {
        final Document aDoc = new Genericode10CodeListMarshaller().write(aCodeList);
        if (aDoc == null)
            throw new IllegalStateException("Failed to serialize code list");
        final OutputStream aFOS = FileUtils.getOutputStream(sFilename);
        if (XMLWriter.writeToStream(aDoc, aFOS, XMLWriterSettings.DEFAULT_XML_SETTINGS).isFailure())
            throw new IllegalStateException("Failed to write file " + sFilename);
        s_aLogger.info("Wrote Genericode file " + sFilename);
    }

    private static void _writeValidationPartyIdFile(final Sheet aParticipantSheet) throws URISyntaxException {
        // Read excel file
        final ExcelReadOptions aReadOptions = new ExcelReadOptions().setLinesToSkip(1).setLineIndexShortName(0);
        aReadOptions.addColumn(0, "code", UseType.REQUIRED, "string", true);
        aReadOptions.addColumn(2, "name", UseType.OPTIONAL, "string", false);

        // Convert to GeneriCode
        final CodeListDocument aCodeList = ExcelSheetToCodeList.convertToSimpleCodeList(aParticipantSheet,
                aReadOptions, "Scheme Agency", CODELIST_VERSION.getAsString(), new URI("PEPPOL"),
                new URI("PEPPOL-" + CODELIST_VERSION.getAsString()), new URI("PartyID.gc"));
        _writeGenericodeFile(aCodeList, RESULT_DIRECTORY + "PartyID.gc");
    }

    private static void _emitIdentifierIssuingAgency(final Sheet aParticipantSheet) throws URISyntaxException {
        // Read excel file
        final ExcelReadOptions aReadOptions = new ExcelReadOptions().setLinesToSkip(1).setLineIndexShortName(0);
        aReadOptions.addColumn(0, "schemeid", UseType.REQUIRED, "string", true);
        aReadOptions.addColumn(1, "iso6523", UseType.REQUIRED, "string", true);
        aReadOptions.addColumn(2, "schemeagency", UseType.OPTIONAL, "string", false);
        aReadOptions.addColumn(3, "deprecated", UseType.REQUIRED, "boolean", false);
        aReadOptions.addColumn(4, "since", UseType.REQUIRED, "string", false);
        aReadOptions.addColumn(6, "structure", UseType.OPTIONAL, "string", false);

        // Convert to GeneriCode
        final CodeListDocument aCodeList = ExcelSheetToCodeList.convertToSimpleCodeList(aParticipantSheet,
                aReadOptions, "PeppolIdentifierIssuingAgencies", CODELIST_VERSION.getAsString(),
                new URI("urn:peppol.eu:names:identifier:issuingagencies"),
                new URI("urn:peppol.eu:names:identifier:issuingagencies-1.0"), null);
        _writeGenericodeFile(aCodeList, RESULT_DIRECTORY + "PeppolIdentifierIssuingAgencies.gc");

        _writeValidationPartyIdFile(aParticipantSheet);

        // Save data also as XML
        final IMicroDocument aDoc = new MicroDocument();
        aDoc.appendComment("This file was automatically generated. Do NOT edit!");
        final IMicroElement eRoot = aDoc.appendElement("root");
        eRoot.setAttribute("version", CODELIST_VERSION.getAsString());
        for (final Row aRow : aCodeList.getSimpleCodeList().getRow()) {
            final String sCode = Genericode10Utils.getRowValue(aRow, "schemeid");
            final String sAgency = Genericode10Utils.getRowValue(aRow, "schemeagency");
            final String sISO6523 = Genericode10Utils.getRowValue(aRow, "iso6523");
            final String sDeprecated = Genericode10Utils.getRowValue(aRow, "deprecated");
            final boolean bDeprecated = StringParser.parseBool(sDeprecated, false);
            final String sSince = Genericode10Utils.getRowValue(aRow, "since");
            final String sStructure = Genericode10Utils.getRowValue(aRow, "structure");

            final IMicroElement eAgency = eRoot.appendElement("issuingAgency");
            eAgency.setAttribute("schemeid", sCode);
            eAgency.setAttribute("agencyname", sAgency);
            eAgency.setAttribute("iso6523", sISO6523);
            if (bDeprecated)
                eAgency.setAttribute("deprecated", Boolean.TRUE.toString());
            eAgency.setAttribute("since", sSince);

            if (StringHelper.hasText(sStructure)) {
                final IMicroElement eStructure = eAgency.appendElement("structure");
                eStructure.appendText(sStructure);
            }
        }
        final String sXML = MicroWriter.getXMLString(aDoc);
        SimpleFileIO.writeFile(new File(RESULT_DIRECTORY + "PeppolIdentifierIssuingAgencies.xml"), sXML,
                CCharset.CHARSET_UTF_8_OBJ);

        // Create Java source
        try {
            final JDefinedClass jEnum = s_aCodeModel._package("at.peppol.commons.identifier.issuingagency")
                    ._enum("EPredefinedIdentifierIssuingAgency")._implements(IIdentifierIssuingAgency.class);
            jEnum.javadoc().add("This file is generated. Do NOT edit!");

            // enum constants
            for (final Row aRow : aCodeList.getSimpleCodeList().getRow()) {
                final String sSchemeID = Genericode10Utils.getRowValue(aRow, "schemeid");
                final String sAgency = Genericode10Utils.getRowValue(aRow, "schemeagency");
                final String sISO6523 = Genericode10Utils.getRowValue(aRow, "iso6523");
                final String sDeprecated = Genericode10Utils.getRowValue(aRow, "deprecated");
                final boolean bDeprecated = StringParser.parseBool(sDeprecated, false);
                final String sSince = Genericode10Utils.getRowValue(aRow, "since");

                if (StringHelper.hasNoText(sSchemeID))
                    throw new IllegalArgumentException("schemeID");
                if (sSchemeID.indexOf(' ') >= 0)
                    throw new IllegalArgumentException("Scheme IDs are not supposed to contain spaces!");
                if (StringHelper.hasNoText(sISO6523))
                    throw new IllegalArgumentException("ISO6523Code");
                if (!RegExHelper.stringMatchesPattern("[0-9]{4}", sISO6523))
                    throw new IllegalArgumentException(
                            "The ISO 6523 code '" + sISO6523 + "' does not consist of 4 numbers");

                final JEnumConstant jEnumConst = jEnum.enumConstant(RegExHelper.getAsIdentifier(sSchemeID));
                jEnumConst.arg(JExpr.lit(sSchemeID));
                jEnumConst.arg(sAgency == null ? JExpr._null() : JExpr.lit(sAgency));
                jEnumConst.arg(JExpr.lit(sISO6523));
                jEnumConst.arg(bDeprecated ? JExpr.TRUE : JExpr.FALSE);
                jEnumConst.arg(JExpr._new(s_aCodeModel.ref(Version.class)).arg(JExpr.lit(sSince)));

                jEnumConst.javadoc().add(
                        "Prefix <code>" + sISO6523 + "</code>, scheme ID <code>" + sSchemeID + "</code><br>\n");
                if (bDeprecated)
                    jEnumConst.javadoc().add(
                            "<b>This item is deprecated and should not be used to issue new identifiers!</b><br>\n");
                jEnumConst.javadoc().add("@since code list " + sSince);
            }

            // fields
            final JFieldVar fSchemeID = jEnum.field(JMod.PRIVATE | JMod.FINAL, String.class, "m_sSchemeID");
            final JFieldVar fSchemeAgency = jEnum.field(JMod.PRIVATE | JMod.FINAL, String.class, "m_sSchemeAgency");
            final JFieldVar fISO6523 = jEnum.field(JMod.PRIVATE | JMod.FINAL, String.class, "m_sISO6523");
            final JFieldVar fDeprecated = jEnum.field(JMod.PRIVATE | JMod.FINAL, boolean.class, "m_bDeprecated");
            final JFieldVar fSince = jEnum.field(JMod.PRIVATE | JMod.FINAL, Version.class, "m_aSince");

            // Constructor
            final JMethod jCtor = jEnum.constructor(JMod.PRIVATE);
            final JVar jSchemeID = jCtor.param(JMod.FINAL, String.class, "sSchemeID");
            jSchemeID.annotate(Nonnull.class);
            jSchemeID.annotate(Nonempty.class);
            final JVar jSchemeAgency = jCtor.param(JMod.FINAL, String.class, "sSchemeAgency");
            jSchemeAgency.annotate(Nullable.class);
            final JVar jISO6523 = jCtor.param(JMod.FINAL, String.class, "sISO6523");
            jISO6523.annotate(Nonnull.class);
            jISO6523.annotate(Nonempty.class);
            final JVar jDeprecated = jCtor.param(JMod.FINAL, boolean.class, "bDeprecated");
            final JVar jSince = jCtor.param(JMod.FINAL, Version.class, "aSince");
            jSince.annotate(Nonnull.class);
            jCtor.body().assign(fSchemeID, jSchemeID).assign(fSchemeAgency, jSchemeAgency)
                    .assign(fISO6523, jISO6523).assign(fDeprecated, jDeprecated).assign(fSince, jSince);

            // public String getSchemeID ()
            JMethod m = jEnum.method(JMod.PUBLIC, String.class, "getSchemeID");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(fSchemeID);

            // public String getSchemeAgency ()
            m = jEnum.method(JMod.PUBLIC, String.class, "getSchemeAgency");
            m.annotate(Nullable.class);
            m.body()._return(fSchemeAgency);

            // public String getISO6523Code ()
            m = jEnum.method(JMod.PUBLIC, String.class, "getISO6523Code");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(fISO6523);

            // public String createIdentifierValue (String)
            final JMethod mCreateIdentifierValue = jEnum.method(JMod.PUBLIC, String.class, "createIdentifierValue");
            mCreateIdentifierValue.annotate(Nonnull.class);
            mCreateIdentifierValue.annotate(Nonempty.class);
            JVar jValue = mCreateIdentifierValue.param(JMod.FINAL, String.class, "sIdentifier");
            jValue.annotate(Nonnull.class);
            jValue.annotate(Nonempty.class);
            mCreateIdentifierValue.body()._return(fISO6523.plus(JExpr.lit(":")).plus(jValue));

            // public SimpleParticipantIdentifier createIdentifierValue (String)
            m = jEnum.method(JMod.PUBLIC, SimpleParticipantIdentifier.class, "createParticipantIdentifier");
            m.annotate(Nonnull.class);
            jValue = m.param(JMod.FINAL, String.class, "sIdentifier");
            jValue.annotate(Nonnull.class);
            jValue.annotate(Nonempty.class);
            m.body()._return(s_aCodeModel.ref(SimpleParticipantIdentifier.class)
                    .staticInvoke("createWithDefaultScheme").arg(JExpr.invoke(mCreateIdentifierValue).arg(jValue)));

            // public boolean isDeprecated ()
            m = jEnum.method(JMod.PUBLIC, boolean.class, "isDeprecated");
            m.body()._return(fDeprecated);

            // public Version getSince ()
            m = jEnum.method(JMod.PUBLIC, Version.class, "getSince");
            m.annotate(Nonnull.class);
            m.body()._return(fSince);
        } catch (final Exception ex) {
            s_aLogger.warn("Failed to create source", ex);
        }
    }

    private static void _emitDocumentIdentifiers(final Sheet aDocumentSheet) throws URISyntaxException {
        // Create GeneriCode file
        final ExcelReadOptions aReadOptions = new ExcelReadOptions().setLinesToSkip(1).setLineIndexShortName(0);
        aReadOptions.addColumn(0, "name", UseType.OPTIONAL, "string", false);
        aReadOptions.addColumn(1, "docid", UseType.REQUIRED, "string", true);
        aReadOptions.addColumn(2, "since", UseType.REQUIRED, "string", false);
        final CodeListDocument aCodeList = ExcelSheetToCodeList.convertToSimpleCodeList(aDocumentSheet,
                aReadOptions, "PeppolDocumentTypeIdentifier", CODELIST_VERSION.getAsString(),
                new URI("urn:peppol.eu:names:identifier:document"),
                new URI("urn:peppol.eu:names:identifier:document-1.0"), null);
        _writeGenericodeFile(aCodeList, RESULT_DIRECTORY + "PeppolDocumentTypeIdentifier.gc");

        // Save as XML
        final IMicroDocument aDoc = new MicroDocument();
        aDoc.appendComment("This file was automatically generated. Do NOT edit!");
        final IMicroElement eRoot = aDoc.appendElement("root");
        eRoot.setAttribute("version", CODELIST_VERSION.getAsString());
        for (final Row aRow : aCodeList.getSimpleCodeList().getRow()) {
            final String sDocID = Genericode10Utils.getRowValue(aRow, "docid");
            final String sName = Genericode10Utils.getRowValue(aRow, "name");
            final String sSince = Genericode10Utils.getRowValue(aRow, "since");

            final IMicroElement eAgency = eRoot.appendElement("document");
            eAgency.setAttribute("id", sDocID);
            eAgency.setAttribute("name", sName);
            eAgency.setAttribute("since", sSince);
        }
        final String sXML = MicroWriter.getXMLString(aDoc);
        SimpleFileIO.writeFile(new File(RESULT_DIRECTORY + "PeppolDocumentTypeIdentifier.xml"), sXML,
                CCharset.CHARSET_UTF_8_OBJ);

        // Create Java source
        try {
            s_jEnumPredefinedDoc = s_aCodeModel._package("at.peppol.commons.identifier.doctype")
                    ._enum("EPredefinedDocumentTypeIdentifier")
                    ._implements(IPeppolPredefinedDocumentTypeIdentifier.class);
            s_jEnumPredefinedDoc.javadoc().add("This file is generated. Do NOT edit!");

            final Set<String> aAllShortcutNames = new HashSet<String>();

            // Add all enum constants
            for (final Row aRow : aCodeList.getSimpleCodeList().getRow()) {
                final String sDocID = Genericode10Utils.getRowValue(aRow, "docid");
                final String sName = Genericode10Utils.getRowValue(aRow, "name");
                final String sSince = Genericode10Utils.getRowValue(aRow, "since");

                // Split ID in it's pieces
                final IPeppolDocumentTypeIdentifierParts aDocIDParts = PeppolDocumentTypeIdentifierParts
                        .extractFromString(sDocID);

                // Assemble extensions
                final JInvocation jExtensions = s_aCodeModel.ref(ContainerHelper.class).staticInvoke("newList");
                for (final String sExtensionID : aDocIDParts.getExtensionIDs())
                    jExtensions.arg(JExpr.lit(sExtensionID));

                final String sEnumConstName = RegExHelper.getAsIdentifier(sDocID);
                final JEnumConstant jEnumConst = s_jEnumPredefinedDoc.enumConstant(sEnumConstName);
                jEnumConst.arg(JExpr._new(s_aCodeModel.ref(PeppolDocumentTypeIdentifierParts.class))
                        .arg(JExpr.lit(aDocIDParts.getRootNS())).arg(JExpr.lit(aDocIDParts.getLocalName()))
                        .arg(JExpr.lit(aDocIDParts.getTransactionID())).arg(jExtensions)
                        .arg(JExpr.lit(aDocIDParts.getVersion())));
                jEnumConst.arg(JExpr.lit(sName));
                jEnumConst.arg(JExpr._new(s_aCodeModel.ref(Version.class)).arg(JExpr.lit(sSince)));
                jEnumConst.javadoc().add("<code>" + sDocID + "</code>\n");
                jEnumConst.javadoc().add("@since code list " + sSince);

                // Also create a shortcut for more readable names
                final String sShortcutName = CodeGenerationUtils.createShortcutDocumentTypeIDName(aDocIDParts);
                if (!aAllShortcutNames.add(sShortcutName))
                    throw new IllegalStateException("The shortcut name " + sShortcutName + " is already used for "
                            + aDocIDParts.toString() + ". Please update the algorithm!");
                final JFieldVar aShortcut = s_jEnumPredefinedDoc.field(JMod.PUBLIC | JMod.STATIC | JMod.FINAL,
                        s_jEnumPredefinedDoc, sShortcutName, jEnumConst);
                aShortcut.javadoc().add("Same as {@link #" + sEnumConstName + "}");
            }

            // fields
            final JFieldVar fParts = s_jEnumPredefinedDoc.field(JMod.PRIVATE | JMod.FINAL,
                    IPeppolDocumentTypeIdentifierParts.class, "m_aParts");
            final JFieldVar fID = s_jEnumPredefinedDoc.field(JMod.PRIVATE | JMod.FINAL, String.class, "m_sID");
            final JFieldVar fCommonName = s_jEnumPredefinedDoc.field(JMod.PRIVATE | JMod.FINAL, String.class,
                    "m_sCommonName");
            final JFieldVar fSince = s_jEnumPredefinedDoc.field(JMod.PRIVATE | JMod.FINAL, Version.class,
                    "m_aSince");

            // Constructor
            final JMethod jCtor = s_jEnumPredefinedDoc.constructor(JMod.PRIVATE);
            final JVar jParts = jCtor.param(JMod.FINAL, IPeppolDocumentTypeIdentifierParts.class, "aParts");
            jParts.annotate(Nonnull.class);
            final JVar jCommonName = jCtor.param(JMod.FINAL, String.class, "sCommonName");
            jCommonName.annotate(Nonnull.class);
            jCommonName.annotate(Nonempty.class);
            final JVar jSince = jCtor.param(JMod.FINAL, Version.class, "aSince");
            jSince.annotate(Nonnull.class);
            jCtor.body().assign(fParts, jParts).assign(fCommonName, jCommonName)
                    .assign(fID, fParts.invoke("getAsDocumentTypeIdentifierValue")).assign(fSince, jSince);

            // public String getScheme ()
            JMethod m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, String.class, "getScheme");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(
                    s_aCodeModel.ref(CIdentifier.class).staticRef("DEFAULT_DOCUMENT_TYPE_IDENTIFIER_SCHEME"));

            // public String getValue ()
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, String.class, "getValue");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(fID);

            // public String getRootNS ()
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, String.class, "getRootNS");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(fParts.invoke(m.name()));

            // public String getLocalName ()
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, String.class, "getLocalName");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(fParts.invoke(m.name()));

            // public String getSubTypeIdentifier ()
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, String.class, "getSubTypeIdentifier");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(fParts.invoke(m.name()));

            // public String getTransactionID ()
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, String.class, "getTransactionID");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(fParts.invoke(m.name()));

            // public List<String> getExtensionIDs ()
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, s_aCodeModel.ref(List.class).narrow(String.class),
                    "getExtensionIDs");
            m.annotate(Nonnull.class);
            m.annotate(ReturnsMutableCopy.class);
            m.body()._return(fParts.invoke(m.name()));

            // public String getAsUBLCustomizationID ()
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, String.class, "getAsUBLCustomizationID");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(fParts.invoke(m.name()));

            // public String getVersion ()
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, String.class, "getVersion");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(fParts.invoke(m.name()));

            // public String getCommonName ()
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, String.class, "getCommonName");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(fCommonName);

            // public String getAsDocumentTypeIdentifierValue ()
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, String.class, "getAsDocumentTypeIdentifierValue");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(fID);

            // public SimpleDocumentTypeIdentifier getAsDocumentTypeIdentifier ()
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, SimpleDocumentTypeIdentifier.class,
                    "getAsDocumentTypeIdentifier");
            m.annotate(Nonnull.class);
            m.body()._return(JExpr._new(s_aCodeModel.ref(SimpleDocumentTypeIdentifier.class)).arg(JExpr._this()));

            // public Version getSince ()
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, Version.class, "getSince");
            m.annotate(Nonnull.class);
            m.body()._return(fSince);

            // public boolean isDefaultScheme ()
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, boolean.class, "isDefaultScheme");
            m.annotate(Nonnull.class);
            m.body()._return(JExpr.lit(true));

            // public String getURIEncoded
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, String.class, "getURIEncoded");
            m.annotate(Nonnull.class);
            m.body()._return(s_aCodeModel.ref(IdentifierUtils.class).staticInvoke("getIdentifierURIEncoded")
                    .arg(JExpr._this()));

            // public String getURIPercentEncoded
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, String.class, "getURIPercentEncoded");
            m.annotate(Nonnull.class);
            m.body()._return(s_aCodeModel.ref(IdentifierUtils.class).staticInvoke("getIdentifierURIPercentEncoded")
                    .arg(JExpr._this()));

            // public IPeppolDocumentTypeIdentifierParts getParts
            m = s_jEnumPredefinedDoc.method(JMod.PUBLIC, IPeppolDocumentTypeIdentifierParts.class, "getParts");
            m.annotate(Nonnull.class);
            m.body()._return(JExpr._this());
        } catch (final Exception ex) {
            s_aLogger.warn("Failed to create source", ex);
        }
    }

    private static void _emitProcessIdentifier(final Sheet aProcessSheet) throws URISyntaxException {
        final ExcelReadOptions aReadOptions = new ExcelReadOptions().setLinesToSkip(1).setLineIndexShortName(0);
        aReadOptions.addColumn(0, "name", UseType.REQUIRED, "string", true);
        aReadOptions.addColumn(1, "id", UseType.REQUIRED, "string", true);
        aReadOptions.addColumn(2, "bisid", UseType.REQUIRED, "string", true);
        aReadOptions.addColumn(3, "docids", UseType.REQUIRED, "string", false);
        aReadOptions.addColumn(4, "since", UseType.REQUIRED, "string", false);
        final CodeListDocument aCodeList = ExcelSheetToCodeList.convertToSimpleCodeList(aProcessSheet, aReadOptions,
                "PeppolProcessIdentifier", CODELIST_VERSION.getAsString(),
                new URI("urn:peppol.eu:names:identifier:process"),
                new URI("urn:peppol.eu:names:identifier:process-1.0"), null);
        _writeGenericodeFile(aCodeList, RESULT_DIRECTORY + "PeppolProcessIdentifier.gc");

        // Save as XML
        final IMicroDocument aDoc = new MicroDocument();
        aDoc.appendComment("This file was automatically generated. Do NOT edit!");
        final IMicroElement eRoot = aDoc.appendElement("root");
        eRoot.setAttribute("version", CODELIST_VERSION.getAsString());
        for (final Row aRow : aCodeList.getSimpleCodeList().getRow()) {
            final String sID = Genericode10Utils.getRowValue(aRow, "id");
            final String sBISID = Genericode10Utils.getRowValue(aRow, "bisid");
            final String sDocIDs = Genericode10Utils.getRowValue(aRow, "docids");
            // Split the document identifier string into a list of single strings,
            // and check if each of them is a valid predefined document identifier
            final List<String> aDocIDs = RegExHelper.getSplitToList(sDocIDs, "\n");
            final String sSince = Genericode10Utils.getRowValue(aRow, "since");

            final IMicroElement eAgency = eRoot.appendElement("process");
            eAgency.setAttribute("id", sID);
            eAgency.setAttribute("bisid", sBISID);
            for (final String sDocID : aDocIDs)
                eAgency.appendElement("document").setAttribute("id", sDocID);
            eAgency.setAttribute("since", sSince);
        }
        final String sXML = MicroWriter.getXMLString(aDoc);
        SimpleFileIO.writeFile(new File(RESULT_DIRECTORY + "PeppolProcessIdentifier.xml"), sXML,
                CCharset.CHARSET_UTF_8_OBJ);

        // Create Java source
        try {
            final JDefinedClass jEnum = s_aCodeModel._package("at.peppol.commons.identifier.process")
                    ._enum("EPredefinedProcessIdentifier")._implements(IPeppolPredefinedProcessIdentifier.class);
            jEnum.javadoc().add("This file is generated. Do NOT edit!");

            // enum constants
            final Set<String> aAllShortcutNames = new HashSet<String>();
            for (final Row aRow : aCodeList.getSimpleCodeList().getRow()) {
                final String sID = Genericode10Utils.getRowValue(aRow, "id");
                final String sBISID = Genericode10Utils.getRowValue(aRow, "bisid");
                final String sDocTypeIDs = Genericode10Utils.getRowValue(aRow, "docids");
                final String sSince = Genericode10Utils.getRowValue(aRow, "since");

                final String sEnumConstName = RegExHelper.getAsIdentifier(sID);
                final JEnumConstant jEnumConst = jEnum.enumConstant(sEnumConstName);
                jEnumConst.arg(JExpr.lit(sID));
                jEnumConst.arg(JExpr.lit(sBISID));
                final JArray jArray = JExpr.newArray(s_jEnumPredefinedDoc);
                for (final String sDocTypeID : RegExHelper.getSplitToList(sDocTypeIDs, "\n")) {
                    // Use the short name for better readability
                    final String sIdentifier = true
                            ? CodeGenerationUtils.createShortcutDocumentTypeIDName(
                                    PeppolDocumentTypeIdentifierParts.extractFromString(sDocTypeID))
                            : RegExHelper.getAsIdentifier(sDocTypeID);
                    jArray.add(s_jEnumPredefinedDoc.staticRef(sIdentifier));
                }
                jEnumConst.arg(jArray);
                jEnumConst.arg(JExpr._new(s_aCodeModel.ref(Version.class)).arg(JExpr.lit(sSince)));
                jEnumConst.javadoc().add(sID);
                jEnumConst.javadoc().add("\n@since code list " + sSince);

                // Emit shortcut name for better readability
                final String sShortcutName = CodeGenerationUtils.createShortcutBISIDName(sBISID);
                if (!aAllShortcutNames.add(sShortcutName))
                    throw new IllegalStateException("The BIS ID shortcut '" + sShortcutName
                            + "' is already used - please review the algorithm!");
                final JFieldVar aShortcut = jEnum.field(JMod.PUBLIC | JMod.STATIC | JMod.FINAL, jEnum,
                        sShortcutName, jEnumConst);
                aShortcut.javadoc().add("Same as {@link #" + sEnumConstName + "}");
            }

            // fields
            final JFieldVar fID = jEnum.field(JMod.PRIVATE | JMod.FINAL, String.class, "m_sID");
            final JFieldVar fBISID = jEnum.field(JMod.PRIVATE | JMod.FINAL, String.class, "m_sBISID");
            final JFieldVar fDocIDs = jEnum.field(JMod.PRIVATE | JMod.FINAL, s_jEnumPredefinedDoc.array(),
                    "m_aDocIDs");
            final JFieldVar fSince = jEnum.field(JMod.PRIVATE | JMod.FINAL, Version.class, "m_aSince");

            // Constructor
            final JMethod jCtor = jEnum.constructor(JMod.PRIVATE);
            final JVar jID = jCtor.param(JMod.FINAL, String.class, "sID");
            jID.annotate(Nonnull.class);
            jID.annotate(Nonempty.class);
            final JVar jBISID = jCtor.param(JMod.FINAL, String.class, "sBISID");
            jBISID.annotate(Nonnull.class);
            jBISID.annotate(Nonempty.class);
            final JVar jDocIDs = jCtor.param(JMod.FINAL, s_jEnumPredefinedDoc.array(), "aDocIDs");
            jDocIDs.annotate(Nonnull.class);
            jDocIDs.annotate(Nonempty.class);
            final JVar jSince = jCtor.param(JMod.FINAL, Version.class, "aSince");
            jSince.annotate(Nonnull.class);
            jCtor.body().assign(fID, jID).assign(fBISID, jBISID).assign(fDocIDs, jDocIDs).assign(fSince, jSince);

            // public String getScheme ()
            JMethod m = jEnum.method(JMod.PUBLIC, String.class, "getScheme");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(s_aCodeModel.ref(CIdentifier.class).staticRef("DEFAULT_PROCESS_IDENTIFIER_SCHEME"));

            // public String getValue ()
            m = jEnum.method(JMod.PUBLIC, String.class, "getValue");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(fID);

            // public String getBISID ()
            m = jEnum.method(JMod.PUBLIC, String.class, "getBISID");
            m.annotate(Nonnull.class);
            m.annotate(Nonempty.class);
            m.body()._return(fBISID);

            // public List<? extends IPredefinedDocumentTypeIdentifier>
            // getDocumentTypeIdentifiers ()
            m = jEnum.method(JMod.PUBLIC,
                    s_aCodeModel.ref(List.class)
                            .narrow(s_aCodeModel.ref(IPeppolPredefinedDocumentTypeIdentifier.class).wildcard()),
                    "getDocumentTypeIdentifiers");
            m.annotate(Nonnull.class);
            m.annotate(ReturnsMutableCopy.class);
            m.body()._return(s_aCodeModel.ref(ContainerHelper.class).staticInvoke("newList").arg(fDocIDs));

            // public SimpleProcessIdentifier getAsProcessIdentifier ()
            m = jEnum.method(JMod.PUBLIC, SimpleProcessIdentifier.class, "getAsProcessIdentifier");
            m.annotate(Nonnull.class);
            m.body()._return(JExpr._new(s_aCodeModel.ref(SimpleProcessIdentifier.class)).arg(JExpr._this()));

            // public Version getSince ()
            m = jEnum.method(JMod.PUBLIC, Version.class, "getSince");
            m.annotate(Nonnull.class);
            m.body()._return(fSince);

            // public boolean isDefaultScheme ()
            m = jEnum.method(JMod.PUBLIC, boolean.class, "isDefaultScheme");
            m.annotate(Nonnull.class);
            m.body()._return(JExpr.lit(true));

            // public String getURIEncoded
            m = jEnum.method(JMod.PUBLIC, String.class, "getURIEncoded");
            m.annotate(Nonnull.class);
            m.body()._return(s_aCodeModel.ref(IdentifierUtils.class).staticInvoke("getIdentifierURIEncoded")
                    .arg(JExpr._this()));

            // public String getURIPercentEncoded
            m = jEnum.method(JMod.PUBLIC, String.class, "getURIPercentEncoded");
            m.annotate(Nonnull.class);
            m.body()._return(s_aCodeModel.ref(IdentifierUtils.class).staticInvoke("getIdentifierURIPercentEncoded")
                    .arg(JExpr._this()));
        } catch (final Exception ex) {
            s_aLogger.warn("Failed to create source", ex);
        }
    }

    public static void main(final String[] args) throws IOException, URISyntaxException {
        // Where is the Excel?
        final IReadableResource aXls = new FileSystemResource(EXCEL_FILE);
        if (!aXls.exists())
            throw new IllegalStateException("The Excel file could not be found!");

        // Interprete as Excel
        final Workbook aWB = new HSSFWorkbook(aXls.getInputStream());

        // Check whether all required sheets are present
        final Sheet aParticipantSheet = aWB.getSheet(SHEET_PARTICIPANT);
        if (aParticipantSheet == null)
            throw new IllegalStateException("The " + SHEET_PARTICIPANT + " sheet could not be found!");
        final Sheet aDocumentSheet = aWB.getSheet(SHEET_DOCUMENT);
        if (aDocumentSheet == null)
            throw new IllegalStateException("The " + SHEET_DOCUMENT + " sheet could not be found!");
        final Sheet aProcessSheet = aWB.getSheet(SHEET_PROCESS);
        if (aProcessSheet == null)
            throw new IllegalStateException("The " + SHEET_PROCESS + " sheet could not be found!");

        // Convert participants
        _emitIdentifierIssuingAgency(aParticipantSheet);

        // Convert document identifiers
        _emitDocumentIdentifiers(aDocumentSheet);

        // Convert processes identifiers
        _emitProcessIdentifier(aProcessSheet);

        // Write all Java source files
        final CodeWriter aWriter = new FileCodeWriter(new File("src/main/java"), CCharset.CHARSET_UTF_8);
        s_aCodeModel.build(aWriter);

        s_aLogger.info("Done creating code");
    }
}