org.eclipse.wst.xsl.jaxp.debug.debugger.DebugRunner.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.wst.xsl.jaxp.debug.debugger.DebugRunner.java

Source

/*******************************************************************************
 * Copyright (c) 2007, 2010 Chase Technology Ltd - http://www.chasetechnology.co.uk
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
 *     David Carver (Intalion) - FindBugs cleanup
 *******************************************************************************/
package org.eclipse.wst.xsl.jaxp.debug.debugger;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.util.Map;
import java.util.Properties;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.sax.SAXSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.wst.xsl.jaxp.debug.invoker.IProcessorInvoker;
import org.eclipse.wst.xsl.jaxp.debug.invoker.PipelineDefinition;
import org.eclipse.wst.xsl.jaxp.debug.invoker.TransformationException;
import org.eclipse.wst.xsl.jaxp.debug.invoker.internal.ConfigurationException;
import org.eclipse.wst.xsl.jaxp.debug.invoker.internal.JAXPSAXProcessorInvoker;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * The entry point to the debug process which is responsible for configuring a
 * debugger and then communicating with the Eclipse process via sockets using a
 * common set of commands.
 * 
 * <ul>
 * <li>instantiates an implementation of <code>IXSLDebugger</code>
 * <li>configures the debugger with the transformation pipeline
 * <li>starts the debugger in a separate thread
 * <li>the main thread is then used to listen to incoming requests and call the
 * appropriate debugger methods
 * </ul>
 * 
 * @author Doug Satchwell
 */
public class DebugRunner {
    private static final Log log = LogFactory.getLog(DebugRunner.class);

    private final BufferedReader requestIn;
    private final Writer requestOut;
    private final Writer eventOut;
    private final Writer generatedStream;
    private Socket eventSocket;
    private Socket requestSocket;
    private Socket generateSocket;

    /**
     * Create a new instance of this using the supplied readers and writers.
     * 
     * @param requestIn
     *            the reader for reading incoming requests
     * @param requestOut
     *            the writer for acknowledging requests
     * @param eventOut
     *            the writer for publishing debug events
     */
    public DebugRunner(BufferedReader requestIn, PrintWriter requestOut, PrintWriter eventOut,
            PrintWriter generatedStream) {
        this.requestOut = requestOut;
        this.requestIn = requestIn;
        this.eventOut = eventOut;
        this.generatedStream = generatedStream;
    }

    /**
     * Create a new instance of this given a request port and an event port.
     * 
     * @param requestPort
     *            the port to listen to requests and send acknowledgements
     * @param eventPort
     *            the port for publishing debug events
     * @throws IOException
     *             if there was a problem opening a socket
     */
    public DebugRunner(int requestPort, int eventPort, int generatePort) throws IOException {
        requestSocket = getSocket(requestPort);
        eventSocket = getSocket(eventPort);
        generateSocket = getSocket(generatePort);
        requestIn = new BufferedReader(new InputStreamReader(requestSocket.getInputStream()));
        requestOut = new PrintWriter(requestSocket.getOutputStream(), true);
        eventOut = new PrintWriter(eventSocket.getOutputStream(), true);
        generatedStream = new BufferedWriter(new PrintWriter(generateSocket.getOutputStream(), true));
    }

    /**
     * This method starts the given debugger in its own thread, and blocks while
     * waiting for incoming requests from the request port, until there are no
     * more requests.
     * 
     * @param debugger
     *            the debugger to start in a thread
     * @throws TransformationException
     *             if a problem occurred while transforming
     * @throws IOException
     */
    public void loop(IXSLDebugger debugger) throws TransformationException, IOException {
        debugger.setEventWriter(eventOut);
        debugger.setGeneratedWriter(generatedStream);
        String inputLine, response;
        // signal we are ready to receive requests
        eventOut.write("ready\n"); //$NON-NLS-1$
        eventOut.flush();
        log.debug("entering loop"); //$NON-NLS-1$
        try {
            while ((inputLine = requestIn.readLine()) != null) {
                response = inputLine;
                log.debug("REQUEST:" + inputLine); //$NON-NLS-1$
                Thread debuggerThread = null;
                if (DebugConstants.REQUEST_START.equals(inputLine)) {
                    debuggerThread = new Thread(debugger, "debugger"); //$NON-NLS-1$
                    debuggerThread.start();
                }
                /*
                 * else if (REQUEST_QUIT.equals(inputLine)) { }
                 */
                else if (DebugConstants.REQUEST_STEP_INTO.equals(inputLine)) {
                    debugger.stepInto();
                } else if (DebugConstants.REQUEST_STEP_OVER.equals(inputLine)) {
                    debugger.stepOver();
                } else if (DebugConstants.REQUEST_STEP_RETURN.equals(inputLine)) {
                    debugger.stepReturn();
                } else if (DebugConstants.REQUEST_SUSPEND.equals(inputLine)) {
                    debugger.suspend();
                } else if (DebugConstants.REQUEST_RESUME.equals(inputLine)) {
                    debugger.resume();
                } else if (DebugConstants.REQUEST_STACK.equals(inputLine)) {
                    response = debugger.stack();
                } else if (inputLine.startsWith(DebugConstants.REQUEST_VARIABLE)) {
                    String data = inputLine.substring(DebugConstants.REQUEST_VARIABLE.length() + 1);
                    int id = Integer.parseInt(data);
                    Variable var = debugger.getVariable(id);
                    log.debug("var " + id + " = " + var); //$NON-NLS-1$ //$NON-NLS-2$
                    response = var.getScope() + "&" + var.getName(); //$NON-NLS-1$
                } else if (inputLine.startsWith(DebugConstants.REQUEST_VALUE)) {
                    String data = inputLine.substring(DebugConstants.REQUEST_VALUE.length() + 1);
                    int id = Integer.parseInt(data);
                    Variable var = debugger.getVariable(id);
                    response = var.getType() + "&" + var.getValueFirstLine(); //$NON-NLS-1$
                } else if (inputLine.startsWith(DebugConstants.REQUEST_ADD_BREAKPOINT)) {
                    int index = inputLine.lastIndexOf(' ');
                    String file = inputLine.substring(DebugConstants.REQUEST_ADD_BREAKPOINT.length() + 1, index);
                    String line = inputLine.substring(index + 1);
                    BreakPoint breakpoint = new BreakPoint(file, Integer.parseInt(line));
                    debugger.addBreakpoint(breakpoint);
                } else if (inputLine.startsWith(DebugConstants.REQUEST_REMOVE_BREAKPOINT)) {
                    int index = inputLine.lastIndexOf(' ');
                    String file = inputLine.substring(DebugConstants.REQUEST_REMOVE_BREAKPOINT.length() + 1, index);
                    String line = inputLine.substring(index + 1);
                    BreakPoint breakpoint = new BreakPoint(file, Integer.parseInt(line));
                    debugger.removeBreakpoint(breakpoint);
                } else {
                    response = "What?"; //$NON-NLS-1$
                }
                // confirm request
                log.debug("RESPONSE:" + response); //$NON-NLS-1$
                requestOut.write(response + "\n"); //$NON-NLS-1$
                requestOut.flush();

                /*
                 * if (REQUEST_QUIT.equals(inputLine)) {
                 * waitForFinish(debuggerThread); break; }
                 */
            }
        } catch (IOException e) {
            throw new TransformationException(e.getMessage(), e);
        }
        log.debug("exited loop"); //$NON-NLS-1$
        eventOut.write("terminated\n"); //$NON-NLS-1$
        eventOut.flush();
    }

    /**
     * Dispose of this - close all open sockets.
     * 
     * @throws IOException
     */
    public void dispose() throws IOException {
        if (requestIn != null) {
            try {
                requestIn.close();
            } catch (IOException e) {
                log.error("Could not close request input stream", e); //$NON-NLS-1$
            }
        }
        if (requestOut != null) {
            requestOut.close();
        }
        if (eventOut != null) {
            eventOut.close();
        }
        if (requestSocket != null) {
            try {
                requestSocket.close();
            } catch (IOException e) {
                log.error("Could not close request socket", e); //$NON-NLS-1$
            }
        }
        if (eventSocket != null) {
            try {
                eventSocket.close();
            } catch (IOException e) {
                log.error("Could not close event socket", e); //$NON-NLS-1$
            }
        }
    }

    private static Socket getSocket(int port) throws IOException {
        InetAddress localhost = InetAddress.getByName("localhost"); //$NON-NLS-1$
        ServerSocket serverSocket = new ServerSocket(port, 5, localhost);
        Socket clientSocket = serverSocket.accept();
        serverSocket.close();
        return clientSocket;
    }

    /**
     * Expected arguments:
     * 
     * <ol>
     * <li>the class name of the invoker
     * <li>the file name of the XML launch configuration file
     * <li>the URL of the source document
     * <li>the file of the output document
     * <li>not used (anything)
     * <li>the class name of the <code>IXSLDebugger</code> instance
     * <li>the port used for requests
     * <li>the port used for debug events
     * <li>the port used for generate events
     * </ol>
     * 
     * @param args
     * @throws ParserConfigurationException 
     * @throws SAXException 
     * @throws IllegalAccessException 
     * @throws InstantiationException 
     * @throws ClassNotFoundException 
     */
    public static void main(String[] args) throws SAXException, ParserConfigurationException,
            ClassNotFoundException, InstantiationException, IllegalAccessException {
        log.info("javax.xml.transform.TransformerFactory=" //$NON-NLS-1$
                + System.getProperty("javax.xml.transform.TransformerFactory")); //$NON-NLS-1$
        log.info("java.endorsed.dirs=" + System.getProperty("java.endorsed.dirs")); //$NON-NLS-1$//$NON-NLS-2$

        String invokerClassName = args[0];
        File launchFile = new File(args[1]);
        String src = args[2];
        String target = args[3];
        String debuggerClassName = args[5];

        log.info("src: " + src); //$NON-NLS-1$
        log.info("target: " + target); //$NON-NLS-1$
        log.info("launchFile: " + launchFile); //$NON-NLS-1$
        log.info("debugger: " + debuggerClassName); //$NON-NLS-1$

        DebugRunner debugRunner = null;
        try {
            final IXSLDebugger debugger = createDebugger(debuggerClassName);
            // create the invoker
            IProcessorInvoker invoker = new JAXPSAXProcessorInvoker() {

                @Override
                protected TransformerFactory createTransformerFactory() {
                    TransformerFactory tFactory = super.createTransformerFactory();
                    debugger.setTransformerFactory(tFactory);
                    return tFactory;
                }

                @Override
                public void addStylesheet(URL stylesheet, Map parameters, Properties outputProperties,
                        URIResolver resolver) throws TransformerConfigurationException {
                    InputSource inputsource = new InputSource(stylesheet.toString());
                    // if required in future, parse the document with line
                    // numbers (to get the end line numbers)
                    // XMLReaderWrapper reader = new
                    // XMLReaderWrapper(createReader());
                    // SAXSource source = new SAXSource(reader,inputsource);
                    addStylesheet(new SAXSource(inputsource), resolver, parameters, outputProperties);
                }

                @Override
                protected Transformer addStylesheet(Source source, URIResolver resolver, Map parameters,
                        Properties outputProperties) throws TransformerConfigurationException {
                    Transformer transformer = super.addStylesheet(source, resolver, parameters, outputProperties);
                    debugger.addTransformer(transformer);
                    return transformer;
                }
            };

            if (args.length == 9) {
                int requestPort = Integer.parseInt(args[6]);
                int eventPort = Integer.parseInt(args[7]);
                int generatePort = Integer.parseInt(args[8]);

                log.debug("requestPort: " + requestPort); //$NON-NLS-1$
                log.debug("eventPort: " + eventPort); //$NON-NLS-1$
                log.debug("generatePort: " + generatePort); //$NON-NLS-1$

                try {
                    debugRunner = new DebugRunner(requestPort, eventPort, generatePort);
                } catch (Exception e) {
                    handleFatalError("Could not instantiate invoker: " + invokerClassName, e); //$NON-NLS-1$
                }
            } else {
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                debugRunner = new DebugRunner(br, new PrintWriter(System.out), new PrintWriter(System.err), null);
                System.out.println("xsl>"); //$NON-NLS-1$
            }

            PipelineDefinition pipeline = new PipelineDefinition(launchFile);
            pipeline.configure(invoker);

            debugger.setInvoker(invoker);
            debugger.setSource(new URL(src));
            debugger.setTarget(new FileWriter(new File(target)));

            debugRunner.loop(debugger);
        } catch (IOException e) {
            handleFatalError(e.getMessage(), e);
        } catch (TransformationException e) {
            handleFatalError(e.getMessage(), e);
        } catch (ConfigurationException e) {
            handleFatalError(e.getMessage(), e);
        }

        finally {
            if (debugRunner != null) {
                try {
                    debugRunner.dispose();
                } catch (IOException e) {
                    handleFatalError(e.getMessage(), e);
                }
            }
        }
    }

    private static IXSLDebugger createDebugger(String classname)
            throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        Class clazz = Class.forName(classname);
        return (IXSLDebugger) clazz.newInstance();
    }

    private static void handleFatalError(String msg, Throwable t) {
        log.fatal(msg, t);
        System.exit(1);
    }
}