You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@xalan.apache.org by Donald Ball <ba...@webslingerZ.com> on 2000/04/19 06:44:58 UTC

new Xalan extension class - Shell

Hi guys. I've recently been working on a fun and exciting project - no,
not cocoon-related for once. I was installing a new server farm here at
webslingerZ and I realized that, despite how much I love UNIX and Linux,
configuring all of the various services sucks. You end up with all sorts
of redundant data all over the place and it's a real administrative hassle
to make global policy changes.

So I wrote me a central XML file that's got all of the user, group, and
virtual server data for the farm and am using stylesheets to generate the
/etc files, apache's httpd.conf, bind's conf files, jserv's conf files,
the linux virtual server conf files, the postfix mail daemon virtual user
alias files, and the analog stats conf files. Clearly an experiment that
got out of hand, but gosh darn it, it was so easy and powerful I just
couldn't help myself.

Xalan's redirect extension class was indispensible in writing the
stylesheets to do some of these tasks. The only other thing I needed Xalan
to do that XSLT itself couldn't handle was invoke commands (e.g. mkdir,
touch, kill -HUP). So I wrote me an extension class called Shell that lets
you do so. I reckoned the code might be of some use either to other folks
crazy enough to do system administration via Xalan, or at least as a
fairly simple example of how to write a Xalan extension class, so I've
attached it the bottom of this email. Thanks for providing such a
versatile and interesting tool.

Oh, if any of you are actually interested in borrowing my system
administration "schema" and/or stylesheets, you have but to ask.

- donald

package com.webslingerZ.xalan;

import java.util.*;
import org.w3c.dom.*;
import org.apache.xalan.xslt.XSLProcessorContext;
import org.apache.xalan.xslt.XSLTEngineImpl;
import org.apache.xalan.xslt.ElemTemplateElement;
import org.apache.xalan.xslt.res.XSLTErrorResources;
import org.apache.xalan.xpath.XObject;
import org.apache.xalan.xslt.StylesheetRoot;
import org.apache.xalan.xslt.ElemExtensionCall;
import java.io.*;
import java.net.URL;
import org.apache.xalan.xpath.xml.*;
import org.apache.xml.serialize.*;
import org.xml.sax.DocumentHandler;

/**
 * <p>This class is an extension function for Xalan that lets you invoke shell
 * commands from XSLT stylesheets. There are two basic commands - env and 
 * execute.</p>
 * <dl>
 * <dt>&lt;shell:env name="PATH" value="/usr/bin:/bin"/&gt;</dt>
 * <dd>Sets the named environmental variable to the given value for all
 * execute commands which appear thereafter. If value is empty, it unsets
 * the environmental variable.</dd>
 * <dt>&lt;shell:execute shell="bash" flag="-c"&gt;<i>commands</i>&lt;/shell:execute&gt;</dt>
 * <dd>Executes the contents of the execute element as a bash script. Note
 * that the contents should probably be text but this class doesn't do
 * any sanity checking. If you're using this, you're probably insane anyway.
 * </dd>
 * </dl>
 *
 * @author <a href="mailto:balld@webslingerZ.com">Donald A. Ball Jr.</a>
 * @version 1.0
 */
public class Shell {

  protected Hashtable env_table = new Hashtable();
  protected static final String default_shell = "bash";
  protected static final String default_shell_command_flag = "-c";

  public void env(XSLProcessorContext context, Element element) {
  	String name = element.getAttribute("name");
	String value = element.getAttribute("value");
	if (value == null || value.equals("")) {
		env_table.remove(name);
	} else {
		env_table.put(name,value);
	}
  }

  public void execute(XSLProcessorContext context, Element elem)
    throws java.net.MalformedURLException,
           java.io.FileNotFoundException,
           java.io.IOException,
           org.xml.sax.SAXException
  {
  	String shell = elem.getAttribute("shell");
	if (shell == null || shell.equals("")) {
		shell = default_shell;
	}
	String flag = elem.getAttribute("flag");
	if (flag == null || flag.equals("")) {
		flag = default_shell_command_flag;
	}
    StringWriter writer = new StringWriter();
    DocumentHandler formatter = makeFormatterListener(context,writer);
    context.processor.writeChildren(formatter, context.stylesheetTree,
      (ElemTemplateElement)elem, context.sourceTree, context.sourceNode, 
	  context.mode);
	formatter.endDocument();
	String envp[] = new String[env_table.size()];
	Enumeration enum = env_table.keys();
	int i = 0;
	while (enum.hasMoreElements()) {
		String name = (String)enum.nextElement();
		envp[i++] = name+'='+(String)env_table.get(name);
	}
	Process process = Runtime.getRuntime().exec(
	  new String[] { shell, flag, writer.toString() },
	  envp
	);
	try {
		int exit_value = process.waitFor();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	byte ary[] = new byte[1024];
	InputStream input = process.getInputStream();
	int read;
	while ((read = input.read(ary)) >= 0) {
		System.out.print(new String(ary,0,read));
	}
	input = process.getErrorStream();
	while ((read = input.read(ary)) >= 0) {
		System.err.print(new String(ary,0,read));
	}
  }

  /**
   * Create a new DocumentHandler, based on attributes of the current 
   * DocumentHandler.
   */
  protected DocumentHandler makeFormatterListener(XSLProcessorContext context,
  	StringWriter writer)
    throws java.net.MalformedURLException,
    java.io.FileNotFoundException,
    java.io.IOException,
    org.xml.sax.SAXException
  {

    StylesheetRoot sr = context.stylesheetTree.m_stylesheetRoot;
    OutputFormat formatter = sr.getOutputFormat();

    DocumentHandler flistener
      = sr.makeSAXSerializer(writer, formatter);

    flistener.startDocument();
    return flistener;
  }

}