//=============================================================================
// Copyright 2006-2013 Daniel W. Dyer
//
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//=============================================================================
package org.uncommons.reportng.mod;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.testng.IReporter;
import org.uncommons.reportng.ReportNGException;
import java.io.*;
import java.util.ResourceBundle;
/**
* Convenient base class for the ReportNG reporters. Provides common functionality.
*
* @author Daniel Dyer
* @author azhukov
* Modifications:
* - add copyImage method for copy a single image file to the output directory.
* - use modification path
*/
public abstract class AbstractReporter implements IReporter {
protected static final String TEMPLATE_EXTENSION = ".vm";
protected static final ReportMetadata META = new ReportMetadata();
private static final String ENCODING = "UTF-8";
private static final String META_KEY = "meta";
private static final String UTILS_KEY = "utils";
private static final ReportNGUtils UTILS = new ReportNGUtils();
private static final String MESSAGES_KEY = "messages";
private static final ResourceBundle MESSAGES = ResourceBundle.getBundle("org.uncommons.reportng.mod.messages.reportng",
META.getLocale());
private final String classpathPrefix;
/**
* @param classpathPrefix Where in the classpath to load templates from.
*/
protected AbstractReporter(String classpathPrefix) {
this.classpathPrefix = classpathPrefix;
Velocity.setProperty("resource.loader", "classpath");
Velocity.setProperty("classpath.resource.loader.class",
"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
if (!META.shouldGenerateVelocityLog()) {
Velocity.setProperty("runtime.log.logsystem.class",
"org.apache.velocity.runtime.log.NullLogSystem");
}
try {
Velocity.init();
} catch (Exception | AssertionError ex) {
throw new ReportNGException("Failed to initialise Velocity.", ex);
}
}
/**
* Helper method that creates a Velocity context and initialises it
* with a reference to the ReportNG utils, report metadata and localised messages.
*
* @return An initialised Velocity context.
*/
protected VelocityContext createContext() {
VelocityContext context = new VelocityContext();
context.put(META_KEY, META);
context.put(UTILS_KEY, UTILS);
context.put(MESSAGES_KEY, MESSAGES);
return context;
}
/**
* Generate the specified output file by merging the specified
* Velocity template with the supplied context.
*/
protected void generateFile(File file,
String templateName,
VelocityContext context) throws IOException {
try (Writer writer = new BufferedWriter(new FileWriter(file))) {
Velocity.mergeTemplate(classpathPrefix + templateName,
ENCODING,
context,
writer);
writer.flush();
}
}
/**
* Copy a single named resource from the classpath to the output directory.
*
* @param outputDirectory The destination directory for the copied resource.
* @param resourceName The filename of the resource.
* @param targetFileName The name of the file created in {@literal outputDirectory}.
* @throws IOException If the resource cannot be copied.
*/
protected void copyClasspathResource(File outputDirectory,
String resourceName,
String targetFileName) throws IOException {
String resourcePath = classpathPrefix + resourceName;
InputStream resourceStream = getClass().getClassLoader().getResourceAsStream(resourcePath);
copyStream(outputDirectory, resourceStream, targetFileName);
}
/**
* Copy a single named file to the output directory.
*
* @param outputDirectory The destination directory for the copied resource.
* @param sourceFile The path of the file to copy.
* @param targetFileName The name of the file created in {@literal outputDirectory}.
* @throws IOException If the file cannot be copied.
*/
protected void copyFile(File outputDirectory,
File sourceFile,
String targetFileName) throws IOException {
try (InputStream fileStream = new FileInputStream(sourceFile)) {
copyStream(outputDirectory, fileStream, targetFileName);
}
}
/**
* Helper method to copy the contents of a stream to a file.
*
* @param outputDirectory The directory in which the new file is created.
* @param stream The stream to copy.
* @param targetFileName The file to write the stream contents to.
* @throws IOException If the stream cannot be copied.
*/
protected void copyStream(File outputDirectory,
InputStream stream,
String targetFileName) throws IOException {
File resourceFile = new File(outputDirectory, targetFileName);
BufferedReader reader = null;
Writer writer = null;
try {
reader = new BufferedReader(new InputStreamReader(stream, ENCODING));
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(resourceFile), ENCODING));
String line = reader.readLine();
while (line != null) {
writer.write(line);
writer.write('\n');
line = reader.readLine();
}
writer.flush();
} finally {
if (reader != null) {
reader.close();
}
if (writer != null) {
writer.close();
}
}
}
/**
* Copy a single image file to the output directory.
*
* @param outputDirectory The directory in which the new file is created.
* @param resourceName The filename of the resource image.
* @param targetFileName The file to write the stream contents to.
* @throws IOException If the stream cannot be copied.
*/
protected void copyImage(File outputDirectory,
String resourceName,
String targetFileName) throws IOException {
String resourcePath = classpathPrefix + resourceName;
InputStream resourceStream = getClass().getClassLoader().getResourceAsStream(resourcePath);
File dst = new File(outputDirectory, targetFileName);
try {
OutputStream out = new FileOutputStream(dst);
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = resourceStream.read(buf)) > 0) {
out.write(buf, 0, len);
}
resourceStream.close();
out.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* Deletes any empty directories under the output directory. These
* directories are created by TestNG for its own reports regardless
* of whether those reports are generated. If you are using the
* default TestNG reports as well as ReportNG, these directories will
* not be empty and will be retained. Otherwise they will be removed.
*
* @param outputDirectory The directory to search for empty directories.
*/
protected void removeEmptyDirectories(File outputDirectory) {
if (outputDirectory.exists()) {
for (File file : outputDirectory.listFiles(new EmptyDirectoryFilter())) {
file.delete();
}
}
}
private static final class EmptyDirectoryFilter implements FileFilter {
public boolean accept(File file) {
return file.isDirectory() && file.listFiles().length == 0;
}
}
}