SeleniumLogger.SeleniumLog.java Source code

Java tutorial

Introduction

Here is the source code for SeleniumLogger.SeleniumLog.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package SeleniumLogger;

/// <summary>

import XMLConfig.XmlConfigurationClass;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;

/// This is the main class that the user instantiates.
/// </summary>
/// 
public final class SeleniumLog {

    private String _LogFilePath;
    private String _ScreenshotsPath;
    private Stack PathStack = new Stack();
    private boolean _FileCreated;

    private Stack _CurrentIndentLevelStack = new Stack();
    private SaveIndents _SavedIndents = new SaveIndents();

    private MessageSettings _MessageSettings = new MessageSettings();

    private boolean Result = true;

    public String OutputFilePath() {
        return _LogFilePath;
    }

    public String ScreenshotsPath() {
        return _ScreenshotsPath;
    }

    private int ActualIndentLevel() {
        return _MessageSettings.indentModel.getCurrentLevel();
    }

    private int PendingIndentLevel() {
        return _MessageSettings.GetPendingLevel();
    }

    private ArrayList<Integer> wdlist = new ArrayList<Integer>();
    private WebDriver driver;
    //public _Config Config = new _Config();
    public XmlConfigurationClass Config = XmlConfigurationClass.Instance();

    private SeleniumLog() {
        this(null, false, false);
    }

    //private SeleniumLog(IWebDriver webdriver = null, bool overwrite = false, bool debug = false)
    private SeleniumLog(WebDriver webdriver, boolean overwrite, boolean debug) {

        if (webdriver != null) {
            driver = webdriver;
        } else {
            driver = null;
        }

        if (overwrite) {
            _LogFilePath = Config.LogFilePath;
            NewFile();
            try {
                Thread.sleep(500);
            } catch (InterruptedException ex) {
            }
            if (overwrite)
                Clear();

            _MessageSettings.TimestampFormat = Config.TimestampFormat;
            _MessageSettings.EnableLogging = Config.EnableSeleniumLog;
        } else {
        }

        if (Config.AutoLaunchSeleniumLogDesktop) {
            try {
                //Process myProcess = new ProcessBuilder(command, arg).start();
                Process logger = new ProcessBuilder(
                        Config.SeleniumLogAppInstallationFolder + "\\SeleniumLog Desktop.exe", Config.LogFilePath)
                                .start();
                /*
                Process logger = new Process();
                logger.StartInfo.FileName = Config.SeleniumLogAppInstallationFolder +  "\\SeleniumLog Desktop.exe";
                logger.StartInfo.Arguments = Config.LogFilePath;
                logger.Start();
                */
            } catch (IOException ex) {
                //Logger.getLogger(SeleniumLog.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    }

    private static SeleniumLog instance = null;

    public static SeleniumLog Instance() {
        return Instance(null, true, false);
    }

    public static SeleniumLog Instance(WebDriver webdriver) {
        return Instance(webdriver, true, false);
    }

    public static SeleniumLog Instance(WebDriver webdriver, boolean overwrite, boolean debug) {
        if (instance == null) {
            instance = new SeleniumLog(webdriver, overwrite, debug);
        } else {
            if (webdriver != null) {
                instance.driver = webdriver;
            }
        }
        return instance;
    }

    public void SaveIndent(String Name) {
        _SavedIndents.Set(Name, PendingIndentLevel());
    }

    public void RestoreIndent(String Name) {
        _MessageSettings.GetPendingLevel();

        int[] irestore = _SavedIndents.Get(Name);
        if (irestore[1] < 0)
            IndentTo(0);
        //Error().Red().WriteLine("ERROR: Cannot restore unknown indent name [" + Name + "]");
        IndentTo(irestore[1]);
        _SavedIndents.DeleteKey(Name, irestore[0]);
    }

    public void ResetResult() {
        Result = true;
    }

    public void PublishResult() {
        if (!Result)
            throw new RuntimeException("Result = false");
        //throw new AssertFailedException();
    }

    /// <summary>
    /// Create an empty file
    /// </summary>
    private void NewFile() {
        //File.writeAllText(_LogFilePath, "");
        try (PrintWriter out = new PrintWriter(_LogFilePath)) {
            out.print("");
        } catch (FileNotFoundException ex) {
            //Logger.getLogger(SeleniumLog.class.getName()).log(Level.SEVERE, null, ex);
        }
        _FileCreated = true;
    }

    /// <summary>
    /// Clear file
    /// </summary>
    private void Clear() {
        NewFile();
    }

    private String FormPathString() {
        String ReturnString = "";
        for (Object obj : PathStack) {
            ReturnString = (obj.toString() + "/" + ReturnString).replaceAll("^/+", "").replaceAll("/+$", "");
        }
        return ReturnString;
    }

    /// <summary>
    /// Write msg string to file.
    /// </summary>
    /// <param name="msg"></param>
    public void WriteLine(String msg, boolean take_screenshot) {
        if (!_MessageSettings.EnableLogging)
            return;

        if (Config.TakeScreenshotOnEveryWriteline) {
            Screenshot();
        } else {
            if (take_screenshot)
                Screenshot();
        }
        int sleepTime = 50;
        _MessageSettings.MessageStr = msg;
        String StrToWrite = _MessageSettings.FormMessageString();
        while (true) {
            try (FileWriter out = new FileWriter(_LogFilePath, true)) {
                out.append(StrToWrite + "\n");
                if (_MessageSettings.indentModel.getEmptyTree())
                    _MessageSettings.indentModel.setEmptyTree(false);
                break;
            } catch (IOException ex) {
                System.err.println("..... Exception: File locked. Message - " + ex.getMessage());
                try {
                    Thread.sleep(sleepTime);
                } catch (InterruptedException ex1) {
                }
                sleepTime *= 2;
                if (sleepTime > 50000) {
                    System.err.println("File lock timeout. WriteLine() failed");
                    break;
                }
            }
        }
    }

    public void WriteLine(String msg) {
        WriteLine(msg, false);
    }

    /// <summary>
    /// true - Display line numbers. false - turn off line numbers.
    /// </summary>
    /// <param name="AddLN"></param>
    /// <returns></returns>
    public SeleniumLog DisplayLineNumbers() {
        _MessageSettings.ShowLineNumbers = true;
        return this;
    }

    public SeleniumLog RemoveLineNumbers() {
        _MessageSettings.ShowLineNumbers = false;
        return this;
    }

    /// <summary>
    /// Indent by one level.
    /// </summary>
    /// <returns></returns>
    public SeleniumLog Indent() {
        _MessageSettings.Indent = _MessageSettings.Indent + 1;
        //MessageSettings.RunningIndentLevel++;
        //MessageSettings.CalculatePendingLevel();
        return this;
    }

    /// <summary>
    /// Set indent to any level specified by SetLevel. Note that SetLevel value has to be an existing level.
    /// </summary>
    /// <param name="SetLevel">Set the level. It will calculate the number of unindents required to set the indent level to this. Base level is 0.</param>
    /// <returns></returns>
    public SeleniumLog IndentTo(int SetLevel) {
        int Delta = SetLevel - _MessageSettings.CurrentIndentLevel();
        if (Delta > 0) {
            _MessageSettings.Indent = 0;
            _MessageSettings.Unindent = 0;
            _MessageSettings.Indent++;
        } else {
            _MessageSettings.Indent = 0;
            _MessageSettings.Unindent = 0;
            Unindent(Math.abs(Delta));
        }
        return this;
    }

    /// <summary>
    /// Indent by one level then write message buffer to file.
    /// </summary>
    /// <param name="WriteNow">Set to true to write message buffer to the file now.</param>
    /// <returns></returns>
    public void Indent(boolean WriteNow) {
        _MessageSettings.Indent++;
        if (WriteNow) {
            String StrToWrite = _MessageSettings.FormMessageString();
            WriteLine(StrToWrite);
        }
    }

    /// <summary>
    /// Unindent by one level. 
    /// </summary>
    /// <returns></returns>
    public SeleniumLog Unindent() {
        if ((_MessageSettings.CurrentIndentLevel() - 1) >= 0)
            _MessageSettings.Unindent = _MessageSettings.Unindent + 1;
        return this;
    }

    /// <summary>
    /// Unindent by multiple levels.
    /// </summary>
    /// <param name="Number">Number of times to unindent.</param>
    /// <returns></returns>
    public SeleniumLog Unindent(int Number) {
        for (int i = 0; i < Math.abs(Number); i++) {
            Unindent();
        }
        return this;
    }

    /// <summary>
    /// Unindent then write message buffer to file.
    /// </summary>
    /// <param name="WriteNow">Set to true to write message buffer to the file now.</param>
    /// <returns></returns>
    public void Unindent(boolean WriteNow) {
        _MessageSettings.Unindent++;
        if (WriteNow) {
            String StrToWrite = _MessageSettings.FormMessageString();
            WriteLine(StrToWrite);
        }
    }

    /// <summary>
    /// Unindent to specified SetLevel. Actually, this is just a wrapper to IndentTo().
    /// </summary>
    /// <param name="SetLevel"></param>
    /// <returns></returns>
    public SeleniumLog UnindentTo(int SetLevel) {
        IndentTo(SetLevel);
        return this;
    }

    /// <summary>
    /// Reset indentation to root level.
    /// </summary>
    /// <returns></returns>
    public SeleniumLog Root() {
        _MessageSettings.Root = true;
        return this;
    }

    /// <summary>
    /// Reset indentation to root level.
    /// </summary>
    /// <param name="WriteNow">Set to true to write message buffer to the file now.</param>
    /// <returns></returns>
    public void Root(boolean WriteNow) {
        _MessageSettings.Root = true;
        if (WriteNow) {
            String StrToWrite = _MessageSettings.FormMessageString();
            WriteLine(StrToWrite);
        }
    }

    /// <summary>
    /// Initiate watchdog feature.
    /// </summary>
    /// <returns></returns>
    private SeleniumLog WatchdogStart() {
        _MessageSettings.WatchdogStart = true;
        boolean containsItem = wdlist.contains(_MessageSettings.CurrentIndentLevel());
        if (containsItem) {
            WriteLine(">>>>>>>>>> wdlist already contains this indentation level!");
        } else {
            wdlist.add(_MessageSettings.CurrentIndentLevel());
        }
        return this;
    }

    /// <summary>
    /// Initiate watchdog feature.
    /// </summary>
    /// <param name="WriteNow">Set to true to write message buffer to the file now.</param>
    /// <returns></returns>
    private SeleniumLog WatchdogStart(boolean WriteNow) {
        _MessageSettings.WatchdogStart = true;
        if (WriteNow) {
            String StrToWrite = _MessageSettings.FormMessageString();
            WriteLine(StrToWrite);
            return null;
        } else {
            return this;
        }
    }

    /// <summary>
    /// Terminate current watchdog which was previously initiated by WatchdogStart.
    /// </summary>
    /// <returns></returns>
    private SeleniumLog WatchdogEnd() {
        _MessageSettings.WatchdogEnd = true;
        boolean containsItem = wdlist.contains(_MessageSettings.CurrentIndentLevel());
        if (containsItem) {
            _MessageSettings.WatchdogEnd = true;
        } else {
        }
        return this;
    }

    /// <summary>
    /// Terminate current watchdog which was previously initiated by WatchdogStart.
    /// </summary>
    /// <param name="WriteNow">Set to true to write message buffer to the file now.</param>
    /// <returns>SeleniumLog object</returns>
    private SeleniumLog WatchdogEnd(boolean WriteNow) {
        _MessageSettings.WatchdogEnd = true;
        if (WriteNow) {
            String StrToWrite = _MessageSettings.FormMessageString();
            //File.AppendAllText(_LogFilePath, StrToWrite + "\n");
            WriteLine(StrToWrite);
            return null;
        } else {
            return this;
        }
    }

    /// <summary>
    /// Pass the step.
    /// </summary>
    /// <returns></returns>
    public SeleniumLog Pass() {
        if (Config.TakeScreenshotOnEveryPass)
            Screenshot();
        Green();
        _MessageSettings.Pass = true;
        return this;
    }

    /// <summary>
    /// Fail the step.
    /// </summary>
    /// <returns></returns>
    public SeleniumLog Fail() {
        if (Config.TakeScreenshotOnEveryFail)
            Screenshot();
        Red();
        _MessageSettings.Fail = true;
        return this;
    }

    /// <summary>
    /// Put a warning icon on the step.
    /// </summary>
    /// <returns></returns>
    public SeleniumLog Warning() {
        if (Config.TakeScreenshotOnEveryWarning)
            Screenshot();
        _MessageSettings.Warning = true;
        return this;
    }

    /// <summary>
    /// Put an error icon on the step.
    /// </summary>
    /// <returns></returns>
    public SeleniumLog Error() {
        if (Config.TakeScreenshotOnEveryError)
            Screenshot();
        _MessageSettings.Error = true;
        return this;
    }

    /// <summary>
    /// Set custom font color. Each component range is 0 to 255.
    /// </summary>
    /// <param name="red">between 0 - 255</param>
    /// <param name="green">between 0 - 255</param>
    /// <param name="blue">between 0 - 255</param>
    /// <returns></returns>
    public SeleniumLog CRGB(int red, int green, int blue) {
        _MessageSettings.CRGB = new Color(red, green, blue);
        return this;
    }

    /// <summary>
    /// Attach a picture file to a step. 
    /// </summary>
    /// <param name="PicturePath"></param>
    /// <returns></returns>
    public SeleniumLog AttachPicture(String PicturePath) {
        _MessageSettings.Image = PicturePath;
        return this;
    }

    /// <summary>
    /// Attach a file of any format to the step. Can also use for pictures.
    /// </summary>
    /// <param name="_FilePath"></param>
    /// <returns></returns>
    private SeleniumLog AttachFile(String FilePath) {
        _MessageSettings.File = FilePath;
        return this;
    }

    public SeleniumLog Path(String PathStr) {
        return Path(PathStr, false);
    }

    /// <summary>
    /// Change the tree path on the left panel. New lines will be added to this path.
    /// </summary>
    /// <param name="PathStr">The tree path separated by / character. Eg., LoginFeature/TestCase1/Setup. If path already exist, then switch to this path.</param>
    /// <param name="WriteNow">Optional. If true, create the path now without having to call Message(str) after it.</param>
    /// <returns></returns>
    public SeleniumLog Path(String PathStr, boolean WriteNow) {
        _MessageSettings.Path = PathStr;
        if (WriteNow) {
            String StrToWrite = _MessageSettings.FormMessageString();
            WriteLine(StrToWrite);
            return null;
        } else {
            return this;
        }
    }

    public SeleniumLog Tab(String TabStr) {
        return Tab(TabStr, false);
    }

    /// <summary>
    /// Change or create new tab. New lines will be added to this tab.
    /// </summary>
    /// <param name="TabStr"></param>
    /// <returns></returns>
    /// 
    /// <summary>
    /// Change or create new tab. New lines will be added to this tab.
    /// </summary>
    /// <param name="TabStr">The name of the tab to be created. If tab already exists, then switch to this tab.</param>
    /// <param name="WriteNow">Optional. If true, create the path now without having to call Message(str) after it.</param>
    /// <returns></returns>
    public SeleniumLog Tab(String TabStr, boolean WriteNow) {
        _MessageSettings.Tab = TabStr;
        if (WriteNow) {
            String StrToWrite = _MessageSettings.FormMessageString();
            WriteLine(StrToWrite);
            return null;
        } else {
            return this;
        }
    }

    /// <summary>
    /// Set timestamp format.
    /// </summary>
    /// <param name="Format"></param>
    /// <returns></returns>
    private SeleniumLog TimestampFormat(String Format) {
        _MessageSettings.TimestampFormat = Format;
        return this;
    }

    public String GetUniqueFilename() {
        return GetUniqueFilename("JPG");
    }

    /// <summary>
    /// Generates a unique filename based on current date/time. This can be used by end-user for screenshots.
    /// </summary>
    /// <returns></returns>
    public String GetUniqueFilename(String Extension) {
        String Filename;
        Date Now = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(Now);

        String Extension2 = Extension.replaceAll("^ *\\.* *", "");
        Filename = "scn_" + Integer.toString(cal.get(Calendar.YEAR)) + "_"
                + Integer.toString(cal.get(Calendar.MONTH + 1)) + "_"
                + Integer.toString(cal.get(Calendar.DAY_OF_MONTH)) + "_"
                + Integer.toString(cal.get(Calendar.HOUR_OF_DAY)) + "_" + Integer.toString(cal.get(Calendar.MINUTE))
                + "_" + Integer.toString(cal.get(Calendar.SECOND)) + "_"
                + Integer.toString(cal.get(Calendar.MILLISECOND)) + "." + Extension2.toLowerCase();

        return Filename;
    }

    public void Test(String msg) {
        try {
            Thread.sleep(50);
            WriteLine(msg);
        } catch (InterruptedException ex) {
        }
    }

    public SeleniumLog Screenshot() {
        SeleniumLog res = null;
        try {
            res = Screenshot(null);
        } catch (Exception ex) {
            Logger.getLogger(SeleniumLog.class.getName()).log(Level.SEVERE, null, ex);
        }
        return res;
    }

    /// <summary>
    /// Pass the step.
    /// </summary>
    /// <returns></returns>
    public SeleniumLog Screenshot(WebDriver _driver) throws Exception {
        try {
            WebDriver scrndriver;
            if (_driver != null)
                scrndriver = _driver;
            else
                scrndriver = driver;

            if (scrndriver == null)
                return this;

            // only take a screenshot if scrndriver is not null. This is so that no exceptions are raised if
            // user sets the config to true in the SeleniumLog.config, but has not set the Selenium Webdriver pointer.
            try {
                String PICTURE_PATH = Config.ScreenshotsFolder + "/" + GetUniqueFilename("jpg");
                TakeScreenshot(scrndriver, PICTURE_PATH);
                //File srcFile = ((TakesScreenshot)scrndriver).getScreenshotAs(OutputType.FILE);
                //Files.copy(srcFile.toPath(), (new File(PICTURE_PATH)).toPath(), REPLACE_EXISTING);
                //Files.delete(srcFile.toPath());

                //byte[] ssb = ((TakesScreenshot)scrndriver).getScreenshotAs(OutputType.BYTES);
                //BufferedImage bi = ImageIO.read(new ByteArrayInputStream(ssb));
                //ImageIO.write(bi, "jpg", new File(PICTURE_PATH));
                //AttachPicture(PICTURE_PATH);
                _MessageSettings.Image = PICTURE_PATH;
            } catch (WebDriverException | IOException | AWTException e) {
                throw e;
            }
            return this;
        } catch (WebDriverException | IOException | AWTException e) {
            Error().WriteLine(e.getMessage());
            throw e;
        }
    }

    private void TakeScreenshot(WebDriver drv, String path) throws IOException, AWTException {
        Rectangle bounds = new Rectangle();
        org.openqa.selenium.Point loc = drv.manage().window().getPosition();
        org.openqa.selenium.Dimension dim = drv.manage().window().getSize();
        bounds.setBounds(loc.getX(), loc.getY(), dim.getWidth(), dim.getHeight());

        Robot robot = new Robot();
        BufferedImage screenShot = robot.createScreenCapture(bounds);
        ImageIO.write(screenShot, "JPG", new File(path));
    }

    public SeleniumLog Red() {
        if (Config.ScreenshotOnEveryMessage)
            Screenshot().CRGB(255, 0, 0);
        else
            CRGB(255, 0, 0);
        return this;
    }

    public void Red(String msg) {
        Red().WriteLine(msg);
    }

    public SeleniumLog Green() {
        CRGB(0, 150, 0);
        return this;
    }

    public void Green(String msg) {
        Green().WriteLine(msg);
    }

    public SeleniumLog Blue() {
        CRGB(0, 0, 250);
        return this;
    }

    public void Blue(String msg) {
        Blue().WriteLine(msg);
    }

    public SeleniumLog Pink() {
        CRGB(247, 91, 208);
        return this;
    }

    public void Pink(String msg) {
        Pink().WriteLine(msg);
    }

    public SeleniumLog Magenta() {
        CRGB(233, 12, 177);
        return this;
    }

    public void Magenta(String msg) {
        Magenta().WriteLine(msg);
    }

    public SeleniumLog Orange() {
        CRGB(250, 97, 5);
        return this;
    }

    public void Orange(String msg) {
        Orange().WriteLine(msg);
    }

    public SeleniumLog Purple() {
        CRGB(97, 0, 193);
        return this;
    }

    public void Purple(String msg) {
        Purple().WriteLine(msg);
    }

    public SeleniumLog Gray() {
        CRGB(135, 135, 135);
        return this;
    }

    public void Gray(String msg) {
        Gray().WriteLine(msg);
    }

    public SeleniumLog BlueGreen() {
        CRGB(13, 115, 71);
        return this;
    }

    public void BlueGreen(String msg) {
        BlueGreen().WriteLine(msg);
    }

    public SeleniumLog Brown() {
        CRGB(113, 0, 0);
        return this;
    }

    public void Brown(String msg) {
        Brown().WriteLine(msg);
    }

    public SeleniumLog Olive() {
        CRGB(128, 128, 0);
        return this;
    }

    public void Olive(String msg) {
        Olive().WriteLine(msg);
    }

    public void Explore(Object arg) {
        Explore(arg, "");
    }

    /// <summary>
    /// Explores any data structure and display the entire tree of elements and values in the log. Works with Lists, Stacks, Queues, etc., or any combination thereof.
    /// </summary>
    /// <param name="arg">The data structure to be explored.</param>
    /// <param name="comment">Optional string to be displayed in the log.</param>
    public void Explore(Object arg, String comment) {
        SeleniumLog log = SeleniumLog.Instance();
        log.SaveIndent("ExploreParams");
        PrintParameters printParameters = new PrintParameters();
        printParameters.PrintValues(arg, comment);
        log.RestoreIndent("ExploreParams");
        //log.MessageSettings.indentModel.SimulateIndentations(MessageSettings.MessageStr);
        log._MessageSettings.GetPendingLevel();
    }

}