All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.legstar.codegen.CodeGenMake Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2015 LegSem.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     LegSem - initial API and implementation
 ******************************************************************************/
package com.legstar.codegen;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * This Ant task iteratively calls the Velocity template engine to create
 * a list of artifacts described in an xml file.
 * The xml file typically describes a target as a sequential list of steps.
 * Each step is associated with a velocity template and produces an artifact.
 * TODO describe the format of xml make in an xsd
 */
public class CodeGenMake extends Task {

    /** The name of the calling generator. */
    private String mGeneratorName;

    /** The cixs make file name. */
    private String mCodeGenMakeFileName;

    /**
     * Velocity templates are applied against a model.
     * This is the model name.
     */
    private String mModelName;

    /**
     * Velocity templates are applied against a model.
     * This is the model itself.
     */
    private Object mModel;

    /** XML element representing a code generation target. */
    public static final String CODEGEN_TARGET_XML_E = "target";

    /** XML attribute representing a code generation target name. */
    public static final String CODEGEN_TARGET_NAME_XML_A = "name";

    /** XML attribute representing a code generation target directory. */
    public static final String CODEGEN_TARGET_DIR_XML_A = "dir";

    /** XML element representing a code generation step with a template. */
    public static final String CODEGEN_STEP_XML_E = "step";

    /** XML attribute representing a code generation template name. */
    public static final String CODEGEN_TEMPLATE_NAME_XML_A = "templateName";

    /** XML attribute representing a code generation target file. */
    public static final String CODEGEN_TEMPLATE_TARGET_FILE_XML_A = "targetFile";

    /** XML attribute representing a code generation target character set. */
    public static final String CODEGEN_TEMPLATE_TARGET_CHARSETNAME_XML_A = "targetCharsetName";

    /** Logger. */
    private final Log _log = LogFactory.getLog(CodeGenMake.class);

    /** @{inheritDoc  */
    @Override
    public void init() {
        try {
            _log.info("Initializing Code generation make processor");
            CodeGenUtil.initVelocity();
        } catch (Exception e) {
            throw new BuildException(e.getMessage());
        }
    }

    /** @{inheritDoc */
    @Override
    public void execute() {
        long start = System.currentTimeMillis();
        try {
            _log.debug("Start make processor");
            Document doc = getInput();
            if (_log.isDebugEnabled()) {
                _log.debug("Make file name   = " + mCodeGenMakeFileName);
                _log.debug("Model name       = " + mModelName);
            }
            processTargets(doc);
        } catch (CodeGenMakeException e) {
            _log.error("Make processor failure", e);
            throw new BuildException(e.getMessage());
        }
        long end = System.currentTimeMillis();
        _log.info("Make processing success for " + mCodeGenMakeFileName);
        _log.info("Duration = " + (end - start) + " ms");
    }

    /**
     * Check input values and load the xml make file.
     * 
     * @return an in-memory DOM xml make
     * @throws CodeGenMakeException if initialization fails
     */
    private Document getInput() throws CodeGenMakeException {
        if (mCodeGenMakeFileName == null || mCodeGenMakeFileName.length() == 0) {
            throw new CodeGenMakeException("Missing make file parameter");
        }
        if (mModelName == null || mModelName.length() == 0) {
            throw new CodeGenMakeException("Missing model name parameter");
        }
        if (mModel == null) {
            throw new CodeGenMakeException("Missing model parameter");
        }
        File makeFile = new File(mCodeGenMakeFileName);

        if (!makeFile.exists()) {
            throw new CodeGenMakeException("Code generation make file "
                    + makeFile + " does not exist");
        }
        return load(makeFile);
    }

    /**
     * Process targets sequentially, invoking the velocity engine for each
     * target.
     * 
     * @param doc a valid DOM for a cixs make
     * @throws CodeGenMakeException if processing fails
     */
    private void processTargets(final Document doc) throws CodeGenMakeException {
        NodeList listOfElements = doc.getElementsByTagName(
                CODEGEN_TARGET_XML_E);
        if (listOfElements == null || listOfElements.getLength() == 0) {
            throw (new CodeGenMakeException(
                    "Empty or invalid code generation make file"));
        }
        Element targetElement = (Element) listOfElements.item(0);
        String targetName = targetElement
                .getAttribute(CODEGEN_TARGET_NAME_XML_A);
        if (targetName == null || targetName.length() == 0) {
            throw new CodeGenMakeException("Missing name attribute for "
                    + CODEGEN_TARGET_XML_E + " element");
        }
        String targetDir = targetElement.getAttribute(CODEGEN_TARGET_DIR_XML_A);
        if (targetDir != null && targetDir.length() > 0) {
            try {
                CodeGenUtil.checkDirectory(targetDir, true);
            } catch (IllegalArgumentException e) {
                throw new CodeGenMakeException(e);
            }
        }
        listOfElements = targetElement.getElementsByTagName(
                CODEGEN_STEP_XML_E);

        if (_log.isDebugEnabled()) {
            _log.debug("Processing target");
            _log.debug("Target name      = " + targetName);
            _log.debug("Target directory = " + targetDir);
        }
        for (int i = 0; i < listOfElements.getLength(); i++) {
            Element templateEl = (Element) listOfElements.item(i);
            String templateName = templateEl.getAttribute(
                    CODEGEN_TEMPLATE_NAME_XML_A);
            if (templateName == null || templateName.length() == 0) {
                throw new CodeGenMakeException(
                        "Missing template name attribute for "
                                + CODEGEN_STEP_XML_E + " element");
            }
            String templateTargetFileName = templateEl.getAttribute(
                    CODEGEN_TEMPLATE_TARGET_FILE_XML_A);
            if (templateTargetFileName == null
                    || templateTargetFileName.length() == 0) {
                throw new CodeGenMakeException(
                        "Missing template target file name attribute for "
                                + CODEGEN_STEP_XML_E + " element");
            }
            String templateTargetCharsetName = templateEl.getAttribute(
                    CODEGEN_TEMPLATE_TARGET_CHARSETNAME_XML_A);
            if (templateTargetCharsetName.length() == 0) {
                templateTargetCharsetName = null;
            }
            CodeGenUtil.processTemplate(
                    mGeneratorName,
                    templateName,
                    mModelName, mModel,
                    getParameters(templateEl),
                    CodeGenUtil.getFile(targetDir, templateTargetFileName),
                    templateTargetCharsetName);
        }
    }

    /**
     * Template elements might have children. These are used to pass additional
     * parameters to the template generation process.
     * Children are expected to have a single value attribute otherwise, they
     * are ignored.
     * 
     * @param templateEl the current template element
     * @return a Map of parameters/values
     */
    private Map < String, Object > getParameters(final Element templateEl) {
        Map < String, Object > parameters = new HashMap < String, Object >();
        NodeList childs = templateEl.getChildNodes();
        for (int i = 0; i < childs.getLength(); i++) {
            if (childs.item(i) instanceof Element) {
                Element parmEl = (Element) childs.item(i);
                String value = parmEl.getAttribute("value");
                if (value != null) {
                    parameters.put(parmEl.getNodeName(), value);
                }
            }
        }
        return parameters;
    }

    /**
     * Loads code generation make file from a serialized XML.
     * 
     * @param makeFile the serialized file
     * @return an in-memory DOM code generation make
     * @throws CodeGenMakeException if load fails
     */
    public Document load(final File makeFile) throws CodeGenMakeException {
        DocumentBuilderFactory docBuilderFactory =
                DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder;
        try {
            docBuilderFactory.setNamespaceAware(false);
            docBuilder = docBuilderFactory.newDocumentBuilder();
            Document doc = docBuilder.parse(makeFile);
            return doc;
        } catch (ParserConfigurationException e) {
            throw (new CodeGenMakeException(e));
        } catch (SAXException e) {
            throw (new CodeGenMakeException(e));
        } catch (IOException e) {
            throw (new CodeGenMakeException(e));
        }
    }

    /**
     * @return the code generation Make File name
     */
    public String getCodeGenMakeFileName() {
        return mCodeGenMakeFileName;
    }

    /**
     * @param codeGenMakeFileName the code generation Make File name to set
     */
    public void setCodeGenMakeFileName(final String codeGenMakeFileName) {
        mCodeGenMakeFileName = codeGenMakeFileName;
    }

    /**
     * @return the model name
     */
    public String getModelName() {
        return mModelName;
    }

    /**
     * @param modelName the model name to set
     */
    public void setModelName(final String modelName) {
        mModelName = modelName;
    }

    /**
     * @return the model used to apply templates to
     */
    public Object getModel() {
        return mModel;
    }

    /**
     * @param model the model to set
     */
    public void setModel(final Object model) {
        mModel = model;
    }

    /**
     * @return the name of the calling generator
     */
    public String getGeneratorName() {
        return mGeneratorName;
    }

    /**
     * @param generatorName the name of the calling generator to set
     */
    public void setGeneratorName(final String generatorName) {
        mGeneratorName = generatorName;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy