//============================================================================= // 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; } } }