Skip to content
This repository has been archived by the owner on Feb 9, 2018. It is now read-only.

Commit

Permalink
Enhanced ProcessWrapperLiteImpl to run a command and return the results
Browse files Browse the repository at this point in the history
This is a breaking change.
  • Loading branch information
Raptor399 committed Nov 24, 2012
1 parent 39fed06 commit 19d83a7
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 16 deletions.
13 changes: 3 additions & 10 deletions src/main/java/net/pms/encoders/AviDemuxerInputStream.java
Expand Up @@ -124,19 +124,12 @@ public void run() {
pipe_process.runInNewThread();
tsPipe.deleteLater();

// Execute the command and ignore the result
String[] cmd = new String[]{ts.executable(), f.getAbsolutePath(), tsPipe.getInputPipe()};
ProcessBuilder pb = new ProcessBuilder(cmd);
process = pb.start();
ProcessWrapper pwi = new ProcessWrapperLiteImpl(process);
attachedProcesses.add(pwi);

// "Gob": a cryptic name for (e.g.) StreamGobbler - i.e. a stream
// consumer that reads and discards the stream
new Gob(process.getErrorStream()).start();
new Gob(process.getInputStream()).start();
ProcessWrapperLiteImpl pwl = new ProcessWrapperLiteImpl(cmd);
pwl.getResult();

realIS = tsPipe.getInputStream();
ProcessUtil.waitFor(process);
LOGGER.trace("tsMuxeR muxing finished");
} catch (IOException e) {
LOGGER.error(null, e);
Expand Down
118 changes: 112 additions & 6 deletions src/main/java/net/pms/io/ProcessWrapperLiteImpl.java
Expand Up @@ -18,49 +18,155 @@
*/
package net.pms.io;

import net.pms.util.ProcessUtil;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Utility class to execute the process of a short running command, for example
* "vlc -version". This in contrary to {@link ProcessWrapperImpl}, which is
* better suited for processes that take a long time to complete
* and that may need to be terminated half way.
* <p>
* Typical use: create an instance, then call {@link getResult()} to execute
* the command and get its output.
*/
public class ProcessWrapperLiteImpl implements ProcessWrapper {
private Process p;
/** Logger */
private static final Logger LOGGER = LoggerFactory.getLogger(ProcessWrapperLiteImpl.class);

/** System program and arguments to execute. */
private String[] command;

/**
* Instantiates a new process wrapper based on the specified operating
* system program and arguments. Instantiating the wrapper does not yet
* execute the command. A call to {@link getResult()} will execute it.
*
* @param command The operating system program and arguments to execute.
*/
public ProcessWrapperLiteImpl(String[] command) {
this.command = command;
}

/**
* Executes the process and returns the combined output and error
* stream as a string. If the command fails to execute, an empty
* string is returned.
* <p>
* Note: this method assumes the command will finish by itself. Execution
* time is not limited in any way and the method will wait for the command
* to finish before returning the result.
*
* @return The combined output and error stream of the process. Individual
* lines will get a "\n" appended.
*/
public String getResult() {
StringBuilder result = new StringBuilder();

if (command == null || command.length == 0) {
return "";
}

ProcessBuilder processBuilder = new ProcessBuilder(command);

// Combine the output and error stream
processBuilder.redirectErrorStream(true);

try {
LOGGER.trace("Executing command \"" + StringUtils.join(command, " ") + "\"");
Process process = processBuilder.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;

while ((line = br.readLine()) != null) {
result.append(line);
result.append("\n");
}

br.close();
isr.close();
is.close();
process.waitFor();
process.destroy();
} catch (IOException e) {
LOGGER.debug("Error executing command \"" + StringUtils.join(command, " ") + "\"", e);
} catch (InterruptedException e) {
LOGGER.debug("Interrupted while waiting for command \"" + StringUtils.join(command, " ")
+ "\" to finish.");
}

public ProcessWrapperLiteImpl(Process p) {
this.p = p;
return result.toString();
}

/**
* Unused interface method.
*
* @return Always returns <code>null</code>.
*/
@Override
public InputStream getInputStream(long seek) throws IOException {
return null;
}

/**
* Unused interface method.
*
* @return Always returns <code>null</code>.
*/
@Override
public ArrayList<String> getResults() {
return null;
}

/**
* Unused interface method.
*
* @return Always returns <code>false</code>.
*/
@Override
public boolean isDestroyed() {
return false;
}

/**
* Unused interface method.
*/
@Override
public void runInNewThread() {
}

/**
* Unused interface method.
*
* @return Always returns <code>false</code>.
*/
@Override
public boolean isReadyToStop() {
return false;
}

/**
* Unused interface method.
*
* @param nullable Parameter is ignored.
*/
@Override
public void setReadyToStop(boolean nullable) {
}

/**
* Unused interface method.
*/
@Override
public void stopProcess() {
ProcessUtil.destroy(p);
}
}
90 changes: 90 additions & 0 deletions src/test/java/net/pms/io/ProcessWrapperLiteImplTest.java
@@ -0,0 +1,90 @@
/*
* PS3 Media Server, for streaming any medias to your PS3.
* Copyright (C) 2008 A.Brochard
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; version 2
* of the License only.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package net.pms.io;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;

import org.junit.Before;
import org.junit.Test;
import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.LoggerContext;

import com.sun.jna.Platform;

/**
* Tests for class ProcessWrapperLiteImpl.
*/
public class ProcessWrapperLiteImplTest {
@Before
public void setUp() {
// Silence all log messages from the PMS code that is being tested
// LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
// context.reset();
}

/**
* Test the basics of the ProcessWrapperLiteImpl class.
*/
@Test
public void testBasics() {
// Null command should return empty string
ProcessWrapperLiteImpl pw = new ProcessWrapperLiteImpl(null);
assertEquals("Result for empty command is empty string", "", pw.getResult());

// Empty command should return empty string
String[] command = {};
pw = new ProcessWrapperLiteImpl(command);
assertEquals("Result for empty command is empty string", "", pw.getResult());

// Non-existing command should return empty string
command = new String[] { "non-existing-command" };
pw = new ProcessWrapperLiteImpl(command);
assertEquals("Result for non existing command is empty string", "", pw.getResult());

// "cd ." should return an empty string on all operating systems.
command = new String[] { "cd", "." };
pw = new ProcessWrapperLiteImpl(command);
assertEquals("Result for \"cd .\" is empty string", "", pw.getResult());
}

/**
* Test commands that return output.
*/
@Test
public void testCommandsWithOutput() {
String[] command;

if (Platform.isWindows()) {
// Windows command that produces output
command = new String[] { "dir", "/s" };
} else {
// Mac OSX and Linux command that produces output
command = new String[] { "ls", "-a" };
}

ProcessWrapperLiteImpl pw = new ProcessWrapperLiteImpl(command);

// It would probably be wise to insert a test for the actual output,
// e.g. to see if it contains a particular string. For now, simply
// test to see whether the result is not empty.
assertFalse("Result for command with output is not empty", "".equals(pw.getResult()));
}
}

0 comments on commit 19d83a7

Please sign in to comment.