FilePrintStreamFactory.java
package org.jbehave.core.reporters;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.jbehave.core.io.CodeLocations;
import org.jbehave.core.io.StoryLocation;
/**
* Creates {@link PrintStream} instances that write to a file identified by the
* {@link StoryLocation}. {@link FileConfiguration} specifies directory and the
* extension, providing useful default values.
*/
public class FilePrintStreamFactory implements PrintStreamFactory {
private final StoryLocation storyLocation;
private FileConfiguration configuration;
private File outputFile;
public FilePrintStreamFactory(StoryLocation storyLocation) {
this(storyLocation, new FileConfiguration());
}
public FilePrintStreamFactory(StoryLocation storyLocation, FileConfiguration configuration) {
this.storyLocation = storyLocation;
this.configuration = configuration;
}
@Override
public PrintStream createPrintStream() {
try {
outputFile = outputFile();
outputFile.getParentFile().mkdirs();
return new FilePrintStream(outputFile, false);
} catch (Exception e) {
throw new PrintStreamCreationFailed(outputFile, e);
}
}
public File getOutputFile() {
return outputFile;
}
public void useConfiguration(FileConfiguration configuration) {
this.configuration = configuration;
this.outputFile = outputFile();
}
public FileConfiguration configuration() {
return configuration;
}
protected File outputFile() {
return new File(outputDirectory(), outputName());
}
/**
* Return the file output directory, using the configured
* {@link FilePathResolver}
*
* @return The File representing the output directory
*/
protected File outputDirectory() {
return new File(configuration.getPathResolver().resolveDirectory(storyLocation,
configuration.getRelativeDirectory()));
}
/**
* Return the file output name, using the configured
* {@link FilePathResolver}
*
* @return The file output name
*/
protected String outputName() {
return configuration.getPathResolver().resolveName(storyLocation, configuration.getExtension());
}
public static interface FilePathResolver {
String resolveDirectory(StoryLocation storyLocation, String relativeDirectory);
String resolveName(StoryLocation storyLocation, String extension);
}
/**
* Resolves directory from code location parent file.
*/
public abstract static class AbstractPathResolver implements FilePathResolver {
@Override
public String resolveDirectory(StoryLocation storyLocation, String relativeDirectory) {
File parent = new File(CodeLocations.getPathFromURL(storyLocation.getCodeLocation())).getParentFile();
return parent.getPath().replace('\\', '/') + "/" + relativeDirectory;
}
}
/**
* Resolves story location path to java packaged name, replacing '/' with '.'
*/
public static class ResolveToPackagedName extends AbstractPathResolver {
@Override
public String resolveName(StoryLocation storyLocation, String extension) {
String name = storyLocation.getPath().replaceAll(":?/", ".");
if (name.startsWith(".")) {
name = name.substring(1);
}
return StringUtils.substringBeforeLast(name, ".") + "." + extension;
}
}
/**
* Resolves story location path to simple name, considering portion after last '/'.
*/
public static class ResolveToSimpleName extends AbstractPathResolver {
@Override
public String resolveName(StoryLocation storyLocation, String extension) {
String name = storyLocation.getPath();
if (StringUtils.contains(name, '/')) {
name = StringUtils.substringAfterLast(name, "/");
}
return StringUtils.substringBeforeLast(name, ".") + "." + extension;
}
}
public static class FilePrintStream extends PrintStream {
private final File outputFile;
private final boolean append;
public FilePrintStream(File outputFile, boolean append) throws FileNotFoundException {
super(new FileOutputStream(outputFile, append));
this.outputFile = outputFile;
this.append = append;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append(outputFile).append(append)
.toString();
}
}
/**
* Configuration class for file print streams. Allows specification the
* relative directory (relative to code location) and file extension.
* Provides as defaults {@link #RELATIVE_DIRECTORY} and {@link #EXTENSION}.
*/
public static class FileConfiguration {
public static final String RELATIVE_DIRECTORY = "jbehave";
public static final String EXTENSION = "html";
private final String relativeDirectory;
private final String extension;
private final FilePathResolver pathResolver;
public FileConfiguration() {
this(EXTENSION);
}
public FileConfiguration(String extension) {
this(RELATIVE_DIRECTORY, extension, new ResolveToPackagedName());
}
public FileConfiguration(String relativeDirectory, String extension, FilePathResolver pathResolver) {
this.relativeDirectory = relativeDirectory;
this.extension = extension;
this.pathResolver = pathResolver;
}
public String getRelativeDirectory() {
return relativeDirectory;
}
public String getExtension() {
return extension;
}
public FilePathResolver getPathResolver() {
return pathResolver;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
@SuppressWarnings("serial")
public class PrintStreamCreationFailed extends RuntimeException {
public PrintStreamCreationFailed(File file, Exception cause) {
super("Failed to create print stream for file " + file, cause);
}
}
}