gt:                         Files.write(path, logFile.getContent(), StandardCharsets.UTF_8);
context: package betsy.bpel.virtual.host.engines;
  
  import java.io.IOException;
  import java.nio.charset.StandardCharsets;
  import java.nio.file.Files;
  import java.nio.file.Path;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Set;
  
  import javax.xml.namespace.QName;
  
  import betsy.bpel.engines.AbstractBPELEngine;
  import betsy.bpel.virtual.common.Constants;
  import betsy.bpel.virtual.common.messages.collect_log_files.LogFile;
  import betsy.bpel.virtual.common.messages.collect_log_files.LogFiles;
  import betsy.bpel.virtual.common.messages.collect_log_files.LogFilesRequest;
  import betsy.bpel.virtual.common.messages.collect_log_files.LogFilesResponse;
  import betsy.bpel.virtual.common.messages.deploy.DeployRequest;
  import betsy.bpel.virtual.host.VirtualBox;
  import betsy.bpel.virtual.host.VirtualBoxException;
  import betsy.bpel.virtual.host.VirtualBoxMachine;
  import betsy.bpel.virtual.host.VirtualEngineAPI;
  import betsy.bpel.virtual.host.comm.HostTcpClient;
  import betsy.bpel.virtual.host.exceptions.PermanentFailedTestException;
  import betsy.bpel.virtual.host.exceptions.TemporaryFailedTestException;
  import betsy.bpel.virtual.host.exceptions.VirtualEngineServiceException;
  import betsy.bpel.virtual.host.exceptions.vm.PortRedirectException;
  import betsy.bpel.virtual.host.exceptions.vm.VirtualMachineNotFoundException;
  import betsy.bpel.virtual.host.virtualbox.SnapshotCreator;
  import betsy.common.config.Configuration;
  import betsy.common.model.engine.EngineExtended;
  import org.apache.log4j.Logger;
  import org.codehaus.groovy.runtime.StackTraceUtils;
  import pebl.ProcessLanguage;
  
  /**
   * A {@link AbstractVirtualBPELEngine} does not install and use an engine server on the
   * current host, but does use an engine installed in a virtualized environment.
   * It therefore offers the same functionality as the default {@link betsy.bpel.engines.AbstractBPELEngine} but
   * also has some more functions to handle the virtualized surrounding.
   *
   * @author Cedric Roeck
   * @version 1.0
   */
  public abstract class AbstractVirtualBPELEngine extends AbstractBPELEngine implements VirtualEngineAPI {
  
      private static final Logger LOGGER = Logger.getLogger(AbstractVirtualBPELEngine.class);
  
      private VirtualBox virtualBox;
      private final HostTcpClient comm = new HostTcpClient(Constants.SERVER_HOSTNAME, Constants.SERVER_PORT);
  
      public AbstractBPELEngine defaultEngine;
  
      private VirtualBoxMachine vm;
  
      @Override
      public EngineExtended getEngineObject() {
          EngineExtended engineId = defaultEngine.getEngineObject();
          List<String> configuration = new LinkedList<>();
          configuration.addAll(engineId.getConfiguration());
          configuration.add("virtual");
          return new EngineExtended(ProcessLanguage.BPEL, engineId.getName(), engineId.getVersion(), engineId.getReleaseDate(), configuration, engineId.getLicense());
      }
  
      public void setVirtualBox(VirtualBox virtualBox) {
          this.virtualBox = virtualBox;
      }
  
      @Override
      public String getVirtualMachineName() {
          return EngineNamingConstants.VIRTUAL_NAME_PREFIX + this.getName();
      }
  
      @Override
      public void startup() {
          if (Configuration.useRunningVM()) {
              return;
          }
  
          LOGGER.info("Startup virtual engine " + getName());
          // required for compatibility with EngineControlGUI
          try {
              // verify port usage
              Set<Integer> ports = getRequiredPorts();
              // also verify the bVMS port
              ports.add(Constants.SERVER_PORT);
  
              // forward and verify used ports
              this.vm.applyPortForwarding(ports);
              setHeadlessMode();
              this.vm.start();
              LOGGER.info("VM started");
          } catch (PortRedirectException exception) {
              throw new TemporaryFailedTestException("The VM could not be "
                      + "started properly:", exception);
          } catch (VirtualBoxException e) {
              throw new PermanentFailedTestException(e);
          }
          LOGGER.trace("startup done!");
      }
  
      private void setHeadlessMode() {
          this.vm.setHeadlessMode(getHeadlessModeOption());
      }
  
      public abstract boolean getHeadlessModeOption();
  
      @Override
      public void shutdown() {
          if (Configuration.useRunningVM()) {
              return;
          }
  
          LOGGER.debug("Shutdown virtual engine " + getName());
          // stop communication
          // if there is no virtualMachine then there is nothing to stop
          if (this.vm != null) {
              if (saveStateInsteadOfShutdown()) {
                  this.vm.saveState();
              } else {
                  this.vm.stop();
              }
          }
          LOGGER.trace("shutdown done!");
      }
  
      public abstract boolean saveStateInsteadOfShutdown();
  
      @Override
      public void install() {
          if (Configuration.useRunningVM()) {
              return;
          }
  
          LOGGER.debug("Install virtualized engine " + getName());
  
          try {
              this.vm = getOrImportVirtualMachine();
              createAndResetToLatestSnapshot();
          } catch (VirtualMachineNotFoundException
                  | VirtualEngineServiceException e) {
              throw new PermanentFailedTestException("The VMs installation "
                      + "could not be processed:", e);
          } catch (PortRedirectException | InterruptedException exception) {
              throw new TemporaryFailedTestException("The VMs installation "
                      + "could not be processed:", exception);
          } catch (VirtualBoxException e) {
              throw new PermanentFailedTestException(e);
          }
          LOGGER.trace("installation done!");
      }
  
      @Override
      public void uninstall() {
          throw new UnsupportedOperationException("uninstall is not supported");
      }
  
      @Override
      public boolean isInstalled() {
          throw new UnsupportedOperationException("uninstall is not supported");
      }
  
      private void createAndResetToLatestSnapshot() throws VirtualBoxException, InterruptedException {
          this.setHeadlessMode();
  
          // need to create a running snapshot
          new SnapshotCreator(this.vm, getName(),  getVerifiableServiceAddresses(), getRequiredPorts()).invoke();
  
          this.vm.restore();
      }
  
      private VirtualBoxMachine getOrImportVirtualMachine() throws VirtualBoxException {
          return virtualBox.importVirtualMachine(getVirtualMachineName(), getName(),
                  Configuration.getVirtualDownloadDir());
      }
  
      @Override
      public void deploy(String name, Path path) {
          try {
              LOGGER.info("Deploying virtualized engine " + getName() + ", process: " + name);
  
              DeployRequest container = buildDeployRequest(name, path);
              comm.deployOperation(container);
              LOGGER.info("deploy done!");
          } catch (Exception exception) {
              LOGGER.error("error during deployment", StackTraceUtils.deepSanitize(exception));
          }
      }
  
      @Override
      public boolean isDeployed(QName process) {
          throw new UnsupportedOperationException("not yet implemented");
      }
  
      @Override
      public void undeploy(QName process) {
          throw new UnsupportedOperationException("not yet implemented");
      }
  
      @Override
      public void storeLogs(Path targetLogPath) {
          LOGGER.debug("Storing logs for engine " + getName());
  
          LogFilesRequest request = buildLogFilesRequest();
  
          try {
              LogFilesResponse response = comm.collectLogFilesOperation(request);
  
              // create log folders
              Files.createDirectories(targetLogPath);
  
              // save to disk...
              for (LogFiles logFiles : response.getLogFiles()) {
  
                  String normalizedFolderPath = logFiles.getFolder().replaceAll("/", "_");
                  Path folder = targetLogPath.resolve(normalizedFolderPath);
                  Files.createDirectories(folder);
  
                  for (LogFile logFile : logFiles.getLogFiles()) {
                      Path path = folder.resolve(logFile.getFilename());
                      try {
  