Package org.syrup.workers

Source Code of org.syrup.workers.DefaultWorker

package org.syrup.workers;

import org.apache.xml.serializer.SerializationHandler;
import org.syrup.Data;
import org.syrup.LogEntry;
import org.syrup.LogEntryTemplate;
import org.syrup.PTask;
import org.syrup.PTaskTemplate;
import org.syrup.WorkSpace;
import org.syrup.helpers.DataImpl;
import org.syrup.helpers.LogEntryTemplateImpl;
import org.syrup.helpers.PTaskTemplateImpl;
import org.syrup.helpers.XMLOutput;
import org.syrup.sql.SQLWorkSpace;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.naming.InitialContext;

/**
* The default Worker implementation that executes PTasks taken from a
* WorkSpace.
*
* @author Robbert van Dalen
*/
public class DefaultWorker
{
    static final String COPYRIGHT = "Copyright 2005 Robbert van Dalen."
        + "At your option, you may copy, distribute, or make derivative works under "
        + "the terms of The Artistic License. This License may be found at "
        + "http://www.opensource.org/licenses/artistic-license.php. "
        + "THERE IS NO WARRANTY; USE THIS PRODUCT AT YOUR OWN RISK.";

    private final static Logger logger = Logger.getLogger("org.syrup.workers.DefaultWorker");

    /**
     * The main entry to start the Worker as a daemon, or to execute a Syrup
     * command.
     *
     * @param args
     *            The command + qualifier.
     * @param i
     *            The InputStream to read input from.
     * @param o
     *            The OutputStream to write output to.
     * @return The number of results (matched/stopped PTasks, matched
     *         LogEntries)
     */
    public static int operate(String[] args, InputStream i, OutputStream o)
        throws Exception
    {  
        WorkSpace sp = null;

        try
        {
            sp = (WorkSpace) (new InitialContext()).lookup("syrupWorkSpace");
        }
        catch (Exception e)
        {
            logger.log(Level.INFO, "Did not get syrupWorkSpace key via JNDI. Reverted to default SQLWorkSpace implementation");
            sp = new SQLWorkSpace();
        }

        if (args.length > 0)
        {

            // The first argument is the command.
            if (args[0].equals("reset"))
            {
                sp.reset();
            }
            else if (args[0].equals("in1"))
            {
                sp.set_in_1(read(i));
            }
            else if (args[0].equals("in2"))
            {
                sp.set_in_2(read(i));
            }
            else if (args[0].equals("out1"))
            {
                write(sp.get_out_1(), o);
            }
            else if (args[0].equals("out2"))
            {
                write(sp.get_out_2(), o);
            }
            else if (args[0].equals("match"))
            {
                PTaskTemplate template = new PTaskTemplateImpl(args);
                return match(sp, template, o);
            }
            else if (args[0].equals("get"))
            {

                PTaskTemplate template = new PTaskTemplateImpl(args);
                return get(sp, template, o);
            }
            else if (args[0].equals("execute"))
            {

                PTaskTemplate template = new PTaskTemplateImpl(args);
                execute(sp, template, -1, 10000);
            }
            else if (args[0].equals("step"))
            {

                PTaskTemplate template = new PTaskTemplateImpl(args);
                execute(sp, template, 1, 0);
            }
            else if (args[0].equals("stop"))
            {
                PTaskTemplate template = new PTaskTemplateImpl(args);
                return stop(sp, template);
            }
            else if (args[0].equals("get-log"))
            {
                // Parses the arguments into a LogEntryTemplate, used by the
                // command.
                LogEntryTemplate template = new LogEntryTemplateImpl(args);
                return match(sp, template, o);
            }
            else
            {
                throw new Exception("operation '"
                    + args[0] + "' not supported");
            }
        }

        return 0;
    }

    /**
     * Start the Worker as a daemon or to execute a Syrup command using
     * System.in and System.out for input and output.
     *
     * @param args
     *            The command + qualifier.
     */
    public static void main(String[] args) throws Exception
    {
        operate(args, System.in, System.out);
    }

    /**
     * Return PTasks that match a PTaskTemplate by writing them out in XML
     * format.
     *
     * @param sp
     *            The WorkSpace to be used.
     * @param template
     *            The PTaskTemplate to be matched.
     * @param out
     *            The OutputStream to write PTasks to.
     * @return The number of matched PTasks.
     */
    public static int match(WorkSpace sp, PTaskTemplate template,
        OutputStream out) throws Exception
    {

        XMLOutput o = new XMLOutput();
        SerializationHandler h = o.wrap(out);

        PTask p[] = sp.match(template);

        // Outputs the fetched PTasks to the OutputStream in XML format.
        o.startDocument("match", h);

        for (int i = 0; i < p.length; i++)
        {
            o.output(p[i], h);
        }

        o.endDocument("match", h);

        return p.length;
    }

    /**
     * Return LogEntries that match a LogEntryTemplate by writing them out in
     * XML format.
     *
     * @param sp
     *            The WorkSpace to be used.
     * @param template
     *            The LogEntryTemplate to be matched.
     * @param out
     *            The OutputStream to write LogEntries to.
     * @return The number of matched LogEntries.
     */

    public static int match(WorkSpace sp, LogEntryTemplate template,
        OutputStream out) throws Exception
    {

        XMLOutput o = new XMLOutput();
        SerializationHandler h = o.wrap(out);

        LogEntry l[] = sp.match(template);

        // Outputs the fetched PTasks to the OutputStream in XML format.
        o.startDocument("log", h);

        for (int i = 0; i < l.length; i++)
        {
            o.output(l[i], h);
        }

        o.endDocument("log", h);

        return l.length;
    }

    /**
     */
    private static void output(Hashtable tree, XMLOutput xmlout,
        SerializationHandler handler) throws Exception
    {
        Iterator keys = tree.keySet().iterator();
        while (keys.hasNext())
        {
            String key = (String) keys.next();
            if (!key.equals("_parent"))
            {
                Object o = tree.get(key);
                if (o instanceof Hashtable)
                {
                    Hashtable subtree = (Hashtable) o;
                    org.syrup.Context c = (org.syrup.Context) subtree.get("_parent");
                    xmlout.start(c, handler);
                    output(subtree, xmlout, handler);
                    xmlout.end(c, handler);
                }
                else
                {
                    xmlout.output((org.syrup.Context) o, handler);
                }
            }
        }
    }

    /**
     * Get the Contexts that match a PTaskTemplate by writing them out in XML
     * format.
     *
     * @param sp
     *            The WorkSpace to be used.
     * @param template
     *            The PTaskTemplate to be matched.
     * @param out
     *            The OutputStream to write Contexts to.
     * @return The number of matched Contexts.
     */
    public static int get(WorkSpace sp, PTaskTemplate template, OutputStream out)
        throws Exception
    {
        XMLOutput o = new XMLOutput();
        SerializationHandler h = o.wrap(out);

        org.syrup.Context c[] = sp.get(template);

        Hashtable parents = new Hashtable();

        // Make a parent Task table
        for (int i = 0; i < c.length; i++)
        {
            org.syrup.Context pc = c[i];
            if (pc.task().isParent())
            {
                Hashtable pn = new Hashtable();
                pn.put("_parent", pc);
                parents.put(pc.task().key(), pn);
            }
        }

        // Put the child Tasks underneath the parent Tasks.
        for (int i = 0; i < c.length; i++)
        {
            org.syrup.Context ct = c[i];
            if (!ct.task().isParent())
            {
                Hashtable pn = (Hashtable) parents.get(ct.task().parentKey());
                if (pn != null)
                {
                    pn.put(ct.task().key(), ct);
                }
                else
                {
                    parents.put(ct.task().key(), ct);
                }
            }
        }

        Hashtable cl = new Hashtable(parents);
        Iterator keys = cl.keySet().iterator();

        // Build hierarchy
        while (keys.hasNext())
        {
            String k = (String) keys.next();
            Object ph = (Object) cl.get(k);
            if (ph instanceof Hashtable)
            {
                Hashtable phh = (Hashtable) ph;
                org.syrup.Context ct = (org.syrup.Context) phh.get("_parent");

                Hashtable oo = (Hashtable) cl.get(ct.task().parentKey());

                if (oo != null)
                {
                    parents.remove(k);
                    oo.put(k, phh);
                }
            }
        }

        // Outputs the fetched Contexts to the OutputStream in XML format.
        o.startDocument("get", h);
        output(parents, o, h);
        o.endDocument("get", h);

        return c.length;
    }

    /**
     * Executes PTasks that match a PTaskTemplate by writing them out in XML
     * format. This method will continue to execute forever, waiting for new
     * PTasks to be executed until the calling Thread or JVM is stopped.
     *
     * @param sp
     *            The WorkSpace to be used.
     * @param template
     *            The PTaskTemplate to be matched.
     */
    public static void execute(WorkSpace sp, PTaskTemplate template,
        long totalIterations, long pollInterval) throws Exception
    {

        try
        {
            while (totalIterations > 0
                || totalIterations < 0)
            {
                PTask p[] = sp.match(template);

                int k = 1;
                int i = 0;
                int executionRuns = 0;

                // Go through all matching PTasks sequentially.
                while (i < p.length)
                {
                    logger.log(Level.INFO, "starting "
                        + p[i], p[i]);

                    PTask p2 = null;
                    int ii = 0;

                    // Retry execution (5 times) upon failure.
                    while (ii++ < 5)
                    {
                        try
                        {
                            p2 = sp.execute(p[i]);
                            executionRuns++;
                            break;
                        }
                        catch (InterruptedException ie)
                        {
                            throw ie;
                        }
                        catch (Exception e)
                        {
                            logger.log(Level.INFO, "execution failed "
                                + p[i], e);
                        }

                        // This block is only entered when execution fails.
                        try
                        {
                            sp.stop(new PTaskTemplateImpl(new String[]
                            {
                                "stop", "-key=equal", " "
                                    + p[i]
                            }));
                        }
                        catch (Exception e)
                        {
                            logger.log(Level.INFO, "stopping failed "
                                + p[i], e);
                        }
                        logger.log(Level.INFO, "... retrying execution "
                            + p[i]);
                    }

                    // Indicates that execution has failed 5 times
                    if (p2 == null)
                    {
                        // Bail out to top level caller.
                        throw new Exception("execution cannot continue - exhausted all retries");
                    }
                    // Indicates that the execution was succesful.
                    if (p2 != p[i])
                    {
                        logger.log(Level.INFO, "executed "
                            + p2, p2);
                    }
                    // Indicates that the execution was not succesful.
                    else
                    {
                        logger.log(Level.INFO, "dropped "
                            + p2, p2);
                    }
                    // Indicates that the PTask was already taken by another
                    // Worker.
                    if (p[i].modifications() == p2.modifications())
                    {
                        // Increase the step taken through the fetched list.
                        // This will lower the chance of hitting a PTask
                        // that has been taken by another Worker.
                        k += 1;
                        logger.log(Level.INFO, "increasing step to "
                            + k);
                    }
                    // Instead of stepping x time, make it x+1, reducing the
                    // chance of colliding with another Worker.
                    // Ideally, the selectopm of executable Tasks from the list
                    // should be random, but this alternative interleaving
                    // scheme is nearly as efficient [TODO: prove this!]
                    i += k;
                }
                try
                {
                    if (executionRuns == 0)
                    {
                        // No more PTasks to be executed. Wait for a while.
                        logger.log(Level.INFO, "sleeping "
                            + pollInterval);
                        Thread.sleep(pollInterval);
                    }
                }
                catch (InterruptedException ie)
                {
                    throw ie;
                }
                catch (Exception e)
                {
                    logger.log(Level.SEVERE, Thread.currentThread().toString(), e);
                }

                if (totalIterations > 0)
                {
                    totalIterations--;
                }
            }
        }
        catch (InterruptedException ie)
        {
            logger.log(Level.WARNING, "interrupted ",
                ie);
        }
        catch (Throwable e)
        {
            logger.log(Level.SEVERE, Thread.currentThread().toString(), e);
        }
    }

    /**
     * Stops a non-progressing PTasks matching the PTaskTemplate.
     *
     * @param sp
     *            The WorkSpace that is used.
     * @param template
     *            The PTaskTemplate to be matched.
     * @return The number of stopped PTasks.
     */
    private static int stop(WorkSpace sp, PTaskTemplate template)
        throws Exception
    {
        int stopped = 0;

        PTask p[] = sp.match(template);

        // Stops the matching PTasks sequentially and one by one.
        for (int i = 0; i < p.length; i++)
        {
            PTask pp = sp.stop(p[i]);
            if (pp != p[i])
            {
                logger.log(Level.INFO, "stopped "
                    + pp);
                stopped++;
            }
        }

        return stopped;
    }

    /**
     * Encapsulates the data read from an InputStream with a Data object.
     *
     * @param i
     *            The InputStream to be encapsulated.
     * @return The encapsulated InputStream.
     */
    private final static Data read(InputStream i) throws Exception
    {
        byte b[] = new byte[8192];
        ByteArrayOutputStream o = new ByteArrayOutputStream(8192);
        int l = 0;

        while ((l = i.read(b)) >= 0)
        {
            o.write(b, 0, l);
        }
        return new DataImpl(o.toByteArray());
    }

    /**
     * Writes the data to an OutputStream using a Data object.
     *
     * @param d
     *            The Data object to be written.
     * @param o
     *            The OutputStream to be written to.
     */
    private final static void write(Data d, OutputStream o) throws Exception
    {
        if (d != null)
        {
            byte[] b = d.bytes();
            o.write(b, 0, b.length);
        }
    }
}
TOP

Related Classes of org.syrup.workers.DefaultWorker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.