/** * $Id: $ * $Date: $ * */ package org.xmlsh.core; import java.io.IOException; import java.io.OutputStream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.xmlsh.core.io.AbstractPort; import org.xmlsh.core.io.OutputPort; import org.xmlsh.core.io.PortList; import org.xmlsh.core.io.ShellIO; import org.xmlsh.core.io.StreamOutputPort; import org.xmlsh.util.AutoReleasePool; import org.xmlsh.util.INameValue; import org.xmlsh.util.NameValue; import org.xmlsh.util.NameValueList; import org.xmlsh.util.PipedPort; import org.xmlsh.util.Util; /* * IO Environment contains a named set of input and output ports. * */ public class XIOEnvironment { private static Logger mLogger = LogManager.getLogger(XIOEnvironment.class); public static final String kSTDERR = "error"; public static final String kSTDIN = "input"; public static final String kSTDOUT = "output"; private PortList<InputPort> mInputs; private PortList<OutputPort> mOutputs; private volatile NameValueList<PipedPort> mPipes; private volatile AutoReleasePool mAutoRelease = null; private <T> T getPort(IHandle<T> hPort) { if(hPort == null) return null; return hPort.get(); } public InputPort getStdin() { return getPort(getInput(kSTDIN)); } /* * Stdandard output stream - created on first request */ public OutputPort getStdout() { return getPort(mOutputs.getPort(kSTDOUT)); } /* * Standard error stream - created on first request */ public OutputPort getStderr() { return getPort(mOutputs.getPort(kSTDERR)); } public InputPort setInput(String name, InputPort port) throws IOException { if(name == null || name.equals(kSTDIN)) { name = kSTDIN; } IHandle<InputPort> in = removeInput(name); if(in != null) in.release(); addInput(name, port); return port; } private void addInput(String name, InputPort port) { synchronized(mInputs) { mInputs.add(name, port); } } private IHandle<InputPort> removeInput(String name) { synchronized(mInputs) { return mInputs.removePort(name); } } public void setOutput(String name, OutputPort port) { IHandle<OutputPort> out; if(name == null) name = kSTDOUT; out = removeOutput(name); if(out != null) Util.safeRelease(out); addOutput(name, port); } private void addOutput(String name, OutputPort port) { synchronized(mOutputs) { mOutputs.add(name, port); } } private IHandle<OutputPort> removeOutput(String name) { synchronized(mOutputs) { return mOutputs.removePort(name); } } /** * @param stderr * the stderr to set * @throws IOException * @throws InvalidArgumentException */ public void setStderr(OutputStream err) throws CoreException { setStderr(new StreamOutputPort(err)); } public void setStderr(OutputPort err) throws CoreException { IHandle<OutputPort> stderr = mOutputs.removePort(kSTDERR); if(stderr != null) Util.safeRelease(stderr); addOutput(kSTDERR, err); } public void release() { try { synchronized(mInputs) { mInputs.close(); mInputs.clear(); } synchronized(mOutputs) { mOutputs.close(); mOutputs.clear(); } if(mAutoRelease != null) { mAutoRelease.close(); mAutoRelease = null; } } catch (Exception e) { mLogger.error("Exception closing environment", e); } } public XIOEnvironment() { mInputs = new PortList<InputPort>(); mOutputs = new PortList<OutputPort>(); } public XIOEnvironment(XIOEnvironment that) { mInputs = new PortList<InputPort>(that.mInputs); mOutputs = new PortList<OutputPort>(that.mOutputs); // Dont copy the AutoRelease pool ... } public void initFromIO(ShellIO io) { mInputs.add( kSTDIN, io.getInputPort()); mOutputs.add( kSTDOUT, io.getOutuptPort()); mOutputs.add( kSTDERR, io.getErrorPort()); } /* * return a named input port * */ public InputPort getInputPort(String name) { IHandle<InputPort> hPort = getInput(name); return hPort == null ? null : hPort.get(); } private IHandle<InputPort> getInput(String name) { synchronized(mInputs) { return mInputs.getPort(name); } } /* * return a named output port * */ public OutputPort getOutputPort(String name) { IHandle<OutputPort> hPort = getOutput(name); return hPort == null ? null : hPort.get(); } private IHandle<OutputPort> getOutput(String name) { synchronized(mOutputs) { return mOutputs.getPort(name); } } public void newPipe(String name, PipedPort pipe) throws CoreException, IOException { setInput(name, pipe.getInput()); setOutput(name, pipe.getOutput()); if(mPipes == null) { synchronized(this) { if(mPipes == null) mPipes = new NameValueList<>(); } } synchronized(mPipes) { mPipes.add(new NameValue<PipedPort>(name, pipe)); } } public PipedPort getPipe(String name) { if(mPipes == null) return null; synchronized(mPipes) { INameValue<PipedPort> nv = mPipes.findName(name); return nv == null ? null : nv.getValue(); } } public void closePipe(String name) { if(mPipes != null) { INameValue<PipedPort> nv = null; PipedPort pipe; synchronized(mPipes) { nv = mPipes.removeName(name); pipe = nv == null ? null : nv.getValue(); } if(pipe != null) { pipe.close(); removeInput(name); removeOutput(name); } } } // "1>&2" public void dupOutput(String portLeft, String portRight) throws IOException { IHandle<OutputPort> hLeft = removeOutput(portLeft); IHandle<OutputPort> hRight = getOutput(portRight); if(hLeft != null) hLeft.release(); if(hRight != null) { // just clear left addOutput(portLeft, hRight.get()); } } public void dupInput(String portLeft, String portRight) throws IOException { IHandle<InputPort> hLeft = removeInput(portLeft); IHandle<InputPort> hRight = getInput(portRight); if(hLeft != null) hLeft.release(); if(hRight != null) { // just clear left addInput(portLeft, hRight.get()); } } public void addAutoRelease(AbstractPort obj) { if(mAutoRelease == null) { synchronized(this) { if(mAutoRelease == null) mAutoRelease = new AutoReleasePool(); } } mAutoRelease.add(obj.newReference()); } } // // // Copyright (C) 2008-2014 David A. Lee. // // The contents of this file are subject to the "Simplified BSD License" (the // "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the // License at http://www.opensource.org/licenses/bsd-license.php // // Software distributed under the License is distributed on an "AS IS" basis, // WITHOUT WARRANTY OF ANY KIND, either express or implied. // See the License for the specific language governing rights and limitations // under the License. // // The Original Code is: all this file. // // The Initial Developer of the Original Code is David A. Lee // // Portions created by (your name) are Copyright (C) (your legal entity). All // Rights Reserved. // // Contributor(s): none. //