Package org.jnode.shell.bjorne

Source Code of org.jnode.shell.bjorne.BjornePipeline$ThreadCallback

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.shell.bjorne;

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

import org.jnode.shell.Command;
import org.jnode.shell.CommandShell;
import org.jnode.shell.CommandThread;
import org.jnode.shell.ShellException;
import org.jnode.shell.ShellFailureException;
import org.jnode.shell.ThreadExitListener;
import org.jnode.shell.io.CommandIO;
import org.jnode.shell.io.CommandIOHolder;
import org.jnode.shell.io.CommandIOMarker;
import org.jnode.shell.io.CommandInput;
import org.jnode.shell.io.CommandOutput;
import org.jnode.shell.io.Pipeline;

/**
* This class deals with construction and running of multi-command
* pipelines for the Bjorne shell. 
*
* @author crawley@jnode.org
*/
class BjornePipeline {
    private static class PipelineStage {
        private String stageName;
        private CommandNode command;
        private BjorneContext context;
        private CommandThread thread;
        private CommandIOHolder[] holders;
        private BjornePipeline nestedPipeline;
    }
   
    private int stageCount = 0;
    private int nextStage = 0;
    private final PipelineStage[] stages;
    private final BjornePipeline parent;
    private final Map<String, Pipeline> pipes;
    private int activeStageCount;
   

    BjornePipeline(int len) {
        this.stages = new PipelineStage[len];
        this.parent = null;
        this.pipes = new HashMap<String, Pipeline>();
    }

    BjornePipeline(BjornePipeline parent, int len) {
        this.stages = new PipelineStage[len];
        this.parent = parent;
        this.pipes = null;
    }

    void closeStreams() {
        for (PipelineStage stage : stages) {
            if (stage != null) {
                for (CommandIOHolder holder : stage.holders) {
                    holder.close();
                }
                if (stage.nestedPipeline != null) {
                    stage.nestedPipeline.closeStreams();
                }
            }
        }
    }

    void wire() throws ShellException {
        createPipes();
        activatePipes();
    }

    private void createPipes() throws ShellFailureException {
        try {
            for (PipelineStage stage : stages) {
                for (CommandIOHolder holder : stage.holders) {
                    CommandIO io = holder.getIO();
                    if (io instanceof CommandIOMarker) {
                        CommandIOMarker marker = (CommandIOMarker) io;
                        String name = marker.getName();

                        if (name.startsWith("PIPE-")) {
                            holder.setIO(
                                    (marker.getDirection() == CommandIO.DIRECTION_OUT ?
                                            getOutPipeIO(name) : getInPipeIO(name)),
                                            true);
                        }
                    }
                }
                if (stage.nestedPipeline != null) {
                    stage.nestedPipeline.createPipes();
                }
            }
        } catch (IOException ex) {
            throw new ShellFailureException("IO error while creating pipes.");
        }
    }

    private CommandIO getOutPipeIO(String name) throws IOException {
        if (parent != null) {
            return parent.getOutPipeIO(name);
        } else {
            Pipeline pipe = pipes.get(name);
            if (pipe == null) {
                pipe = new Pipeline();
                pipes.put(name, pipe);
            }
            return new CommandOutput(pipe.createSource());
        }
    }

    private CommandIO getInPipeIO(String name) throws IOException {
        if (parent != null) {
            return parent.getInPipeIO(name);
        } else {
            Pipeline pipe = pipes.get(name);
            if (pipe == null) {
                pipe = new Pipeline();
                pipes.put(name, pipe);
            }
            return new CommandInput(pipe.createSink());
        }
    }
   
    private void activatePipes() {
        for (Pipeline pipe : pipes.values()) {
            try {
                pipe.activate();
            } catch (IOException ex) {
                pipe.shutdown();
            }
        }
    }

    int run(CommandShell shell) throws ShellException {
        for (PipelineStage stage : stages) {
            stage.thread = stage.command.fork(shell, stage.context);
        }
        activeStageCount = stages.length;
        synchronized (this) {
            for (PipelineStage stage : stages) {
                ThreadCallback callback = new ThreadCallback(stage.context);
                if (stage.thread != null) {
                    stage.thread.start(callback);
                } else {
                    callback.notifyThreadExited(null);
                }
            }
            while (activeStageCount > 0) {
                try {
                    this.wait();
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
            CommandThread lastThread = stages[stages.length - 1].thread;
            return (lastThread == null) ? 0 : lastThread.getReturnCode();
        }
    }

    void addStage(CommandNode commandNode, BjorneContext context) throws ShellException {
        int i = nextStage++;
        PipelineStage stage = stages[i] = new PipelineStage();
        stage.stageName = stageName();
        stage.command = commandNode;
        stage.holders = context.getHolders();
        if (i > 0) {
            String pipeName = "PIPE-" + stages[i - 1].stageName;
            stages[i - 1].holders[Command.STD_OUT].setIO(
                    new CommandIOMarker(pipeName, CommandIO.DIRECTION_OUT), true);
            stage.holders[Command.STD_IN].setIO(
                    new CommandIOMarker(pipeName, CommandIO.DIRECTION_IN), true);
        }
        stage.context = context;
        stage.nestedPipeline = commandNode.buildPipeline(context);
        context.evaluateRedirections(commandNode.getRedirects(), stage.holders);
    }

    private String stageName() {
        return (parent != null) ? parent.stageName() : ("STAGE-" + ++stageCount);
    }

    private class ThreadCallback implements ThreadExitListener {
        private BjorneContext context;

        public ThreadCallback(BjorneContext context) {
            this.context = context;
        }

        public void notifyThreadExited(CommandThread thread) {
            synchronized (BjornePipeline.this) {
                context.closeIOs();
                activeStageCount--;
                if (activeStageCount <= 0) {
                    BjornePipeline.this.notify();
                }
            }
        }
    }
}
TOP

Related Classes of org.jnode.shell.bjorne.BjornePipeline$ThreadCallback

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.