de.betterform.connector.ant.AntSubmissionHandler.java Source code

Java tutorial

Introduction

Here is the source code for de.betterform.connector.ant.AntSubmissionHandler.java

Source

/*
 * Copyright (c) 2012. betterFORM Project - http://www.betterform.de
 * Licensed under the terms of BSD License
 * Author: Tobi Krebs (tobias.krebs AT betterform.de)
 */

package de.betterform.connector.ant;

import de.betterform.connector.AbstractConnector;
import de.betterform.connector.SubmissionHandler;
import de.betterform.xml.dom.DOMUtil;
import de.betterform.xml.xforms.XFormsProcessor;
import de.betterform.xml.xforms.exception.XFormsException;
import de.betterform.xml.xforms.model.submission.Submission;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;

/*
 * A Submissionhandler which allows one to run Ant-Files on the Server. The ant-build-file has to be accessible by the server for this two work.
 *
 * Basic syntax for the submissionhandler is :
 *  ant://<PATH-To-BUILD-FILE>[#TARGET]
 *
 * There exist two ways of invoking a target inside an ant-file via the submission handler:
 *
 * 1. As Fragment-Parameter:
 *   You can specify the desired target as part of the resource URI via an Fragment-Attribute:
 *
 *   e.g. to run the target "test" for the build-file "build-test.xml" (absolute path: /opt/tomcat/webapps/betterform/build-files/build-test.xml) you would specify an resource-URI like this:
 *      ant://{$webapp.realpath}/build-files/build-test.xml#test
 *   a submission declaration could look like this:
 *         <xf:submission id="s-ant-uri-target"
 *              method="get"
 *              replace="none"
 *              ref="instance()"
 *              validate="false"
 *              resource="ant://{$webapp.realpath}/build-files/build-test.xml#test">
 *
 * 2. Via an instance-element "target".
 *   As alternative you can specify the target via an "target"-element (<target/>) inside an instance.
 *   You can only specify one target per instance right now.
 *
 *   Sample instance:
 *   <xf:instance id="i-target">
 *      <data xmlns="">
 *          <target>test</target>
 *      </data>
 *  </xf:instance>
 *
 *  The resource-URI would then look like this:
 *      ant://{$webapp.realpath}/build-files/build-test.xml
 *
 *  And the Submission :
 *         <xf:submission id="s-ant-uri-target"
 *              method="get"
 *              replace="none"
 *              ref="instance('i-target')"
 *              validate="false"
 *              resource="ant://{$webapp.realpath}/build-files/build-test.xml">
 *
 *
 *  The results form the "ant-run" will be return by the submission-handler inside the SUBMISSION_RESPONSE_STREAM in the following format:
 *
 *  <ant>
 *      <buildFile>PATH-TO-BUILD-FILE</buildFile>
 *      <target>TARGET-WHICH-HAS-BEEN-RUN</target>
 *      <output-stream>OUTPUT-OF-SYSTEM-OUT</output-stream>
 *      <error-stream>OUTPUT-OF-SYSTEM-ERROR</error-stream>
 *  </ant>
 */
public class AntSubmissionHandler extends AbstractConnector implements SubmissionHandler {
    /**
    * The logger.
    */
    private static Log LOGGER = LogFactory.getLog(AntSubmissionHandler.class);
    private String buildFile = "build.xml";

    public Map submit(Submission submission, Node instance) throws XFormsException {
        LOGGER.debug("AntSubmissionHandler.submit()");
        ByteArrayOutputStream stream = new ByteArrayOutputStream();

        if (submission.getMethod().equals("get")) {
            try {
                String uri = getURI();
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                ByteArrayOutputStream errorStream = new ByteArrayOutputStream();

                String buildFilePath = (new URI(uri)).getSchemeSpecificPart()
                        .substring((new URI(uri)).getSchemeSpecificPart().indexOf(':') + 1);
                if (!"".equals(buildFilePath)) {
                    File buildFile = new File(buildFilePath);
                    String target = null;
                    if (uri.contains("#")) {
                        //got Traget from uri
                        target = uri.substring(uri.indexOf('#') + 1);
                    } else if (((Document) instance).getElementsByTagName("target").item(0) != null) {
                        //got target from xform
                        target = ((Document) instance).getElementsByTagName("target").item(0).getTextContent();
                    } else {
                        // use default target
                        target = "default";
                    }

                    LOGGER.debug("AntSubmissionHandler.runTarget() BuildFile: " + buildFile.getAbsolutePath()
                            + " with Target:" + target);
                    runTarget(buildFile, target, outputStream, errorStream);

                    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                    factory.setNamespaceAware(true);
                    factory.setValidating(false);
                    Document document = factory.newDocumentBuilder().newDocument();
                    document.appendChild(document.createElementNS(null, "ant"));

                    Element rootElement = document.getDocumentElement();
                    Attr filename = document.createAttribute("fileName");
                    filename.setValue(buildFile.getName());
                    rootElement.setAttributeNode(filename);
                    Element element = document.createElement("buildFile");
                    DOMUtil.setElementValue(element, buildFile.getAbsolutePath());
                    rootElement.appendChild(element);

                    element = document.createElement("target");
                    DOMUtil.setElementValue(element, target);
                    rootElement.appendChild(element);

                    element = document.createElement("output-stream");
                    DOMUtil.setElementValue(element, outputStream.toString());
                    rootElement.appendChild(element);

                    element = document.createElement("error-stream");
                    DOMUtil.setElementValue(element, errorStream.toString());
                    rootElement.appendChild(element);
                    DOMUtil.prettyPrintDOM(document, stream);
                } else {
                    throw new XFormsException("submission method '" + submission.getMethod() + "' at: "
                            + DOMUtil.getCanonicalPath(submission.getElement()) + " not supported");
                }
            } catch (Exception e) {
                throw new XFormsException(e);
            }
        } else {
            throw new XFormsException("submission method '" + submission.getMethod() + "' at: "
                    + DOMUtil.getCanonicalPath(submission.getElement()) + " not supported");
        }

        Map response = new HashMap();
        response.put(XFormsProcessor.SUBMISSION_RESPONSE_STREAM, new ByteArrayInputStream(stream.toByteArray()));
        return response;
    }

    private void runTarget(File buildFile, String target, ByteArrayOutputStream outputStream,
            ByteArrayOutputStream errorStream) throws Exception {
        Project project = new Project();
        DefaultLogger consoleLogger = new DefaultLogger();
        project.addBuildListener(consoleLogger);
        consoleLogger.setErrorPrintStream(new PrintStream(errorStream));
        consoleLogger.setOutputPrintStream(new PrintStream(outputStream));
        consoleLogger.setMessageOutputLevel(Project.MSG_INFO);

        project.setUserProperty("ant.file", buildFile.getAbsolutePath());
        project.init();
        ProjectHelper projectHelper = ProjectHelper.getProjectHelper();
        project.addReference("ant.projectHelper", projectHelper);
        projectHelper.parse(project, buildFile);
        if ("default".equals(target)) {
            String defaultTarget = project.getDefaultTarget();
            if (defaultTarget != null) {
                project.executeTarget(defaultTarget);
            } else {
                throw new XFormsException(
                        "No target was given for Ant file and no default target is present on the build file");
            }

        } else {
            project.executeTarget(target);
        }

    }
}