@Override
  public void execute() throws MojoExecutionException {

    Path warExecFile = Paths.get(buildDirectory, finalName);
    try {
      Files.deleteIfExists(warExecFile);
      Files.createDirectories(warExecFile.getParent());

      try (OutputStream os = Files.newOutputStream(warExecFile);
          ArchiveOutputStream aos =
              new ArchiveStreamFactory().createArchiveOutputStream(ArchiveStreamFactory.JAR, os)) {

        // If project is a war project add the war to the project
        if ("war".equalsIgnoreCase(project.getPackaging())) {
          File projectArtifact = project.getArtifact().getFile();
          if (projectArtifact != null && Files.exists(projectArtifact.toPath())) {
            aos.putArchiveEntry(new JarArchiveEntry(projectArtifact.getName()));
            try (InputStream is = Files.newInputStream(projectArtifact.toPath())) {
              IOUtils.copy(is, aos);
            }
            aos.closeArchiveEntry();
          }
        }

        // Add extraWars into the jar
        if (extraWars != null) {
          for (Dependency extraWarDependency : extraWars) {
            ArtifactRequest request = new ArtifactRequest();
            request.setArtifact(
                new DefaultArtifact(
                    extraWarDependency.getGroupId(),
                    extraWarDependency.getArtifactId(),
                    extraWarDependency.getType(),
                    extraWarDependency.getVersion()));
            request.setRepositories(projectRepos);
            ArtifactResult result;
            try {
              result = repoSystem.resolveArtifact(repoSession, request);
            } catch (ArtifactResolutionException e) {
              throw new MojoExecutionException(e.getMessage(), e);
            }

            File extraWarFile = result.getArtifact().getFile();
            aos.putArchiveEntry(new JarArchiveEntry(extraWarFile.getName()));
            try (InputStream is = Files.newInputStream(extraWarFile.toPath())) {
              IOUtils.copy(is, aos);
            }
            aos.closeArchiveEntry();
          }
        }

        // Add extraResources into the jar. Folder /extra
        if (extraResources != null) {
          for (Resource extraResource : extraResources) {
            DirectoryScanner directoryScanner = new DirectoryScanner();
            directoryScanner.setBasedir(extraResource.getDirectory());

            directoryScanner.setExcludes(
                extraResource
                    .getExcludes()
                    .toArray(new String[extraResource.getExcludes().size()]));

            if (!extraResource.getIncludes().isEmpty()) {
              directoryScanner.setIncludes(
                  extraResource
                      .getIncludes()
                      .toArray(new String[extraResource.getIncludes().size()]));
            } else {
              // include everything by default
              directoryScanner.setIncludes(new String[] {"**"});
            }

            directoryScanner.scan();
            for (String includeFile : directoryScanner.getIncludedFiles()) {
              aos.putArchiveEntry(
                  new JarArchiveEntry(Runner.EXTRA_RESOURCES_DIR + "/" + includeFile));

              Path extraFile = Paths.get(extraResource.getDirectory(), includeFile);
              try (InputStream is = Files.newInputStream(extraFile)) {
                IOUtils.copy(is, aos);
              }
              aos.closeArchiveEntry();
            }
          }
        }

        Set<String> includeArtifacts = new HashSet<>();
        includeArtifacts.add("org.apache.tomcat:tomcat-jdbc");
        includeArtifacts.add("org.apache.tomcat.embed:tomcat-embed-core");
        includeArtifacts.add("org.apache.tomcat.embed:tomcat-embed-logging-juli");
        includeArtifacts.add("org.yaml:snakeyaml");
        includeArtifacts.add("com.beust:jcommander");

        if (includeJSPSupport) {
          includeArtifacts.add("org.apache.tomcat.embed:tomcat-embed-jasper");
          includeArtifacts.add("org.eclipse.jdt.core.compiler:ecj");
        }

        for (Artifact pluginArtifact : pluginArtifacts) {
          String artifactName = pluginArtifact.getGroupId() + ":" + pluginArtifact.getArtifactId();
          if (includeArtifacts.contains(artifactName)) {
            try (JarFile jarFile = new JarFile(pluginArtifact.getFile())) {
              extractJarToArchive(jarFile, aos);
            }
          }
        }

        if (extraDependencies != null) {
          for (Dependency dependency : extraDependencies) {

            ArtifactRequest request = new ArtifactRequest();
            request.setArtifact(
                new DefaultArtifact(
                    dependency.getGroupId(),
                    dependency.getArtifactId(),
                    dependency.getType(),
                    dependency.getVersion()));
            request.setRepositories(projectRepos);
            ArtifactResult result;
            try {
              result = repoSystem.resolveArtifact(repoSession, request);
            } catch (ArtifactResolutionException e) {
              throw new MojoExecutionException(e.getMessage(), e);
            }

            try (JarFile jarFile = new JarFile(result.getArtifact().getFile())) {
              extractJarToArchive(jarFile, aos);
            }
          }
        }

        if (includeJSPSupport) {
          addFile(aos, "/conf/web.xml", "conf/web.xml");
        } else {
          addFile(aos, "/conf/web_wo_jsp.xml", "conf/web.xml");
        }
        addFile(aos, "/conf/logging.properties", "conf/logging.properties");

        if (includeTcNativeWin32 != null) {
          aos.putArchiveEntry(new JarArchiveEntry("tcnative-1.dll.32"));
          Files.copy(Paths.get(includeTcNativeWin32), aos);
          aos.closeArchiveEntry();
        }

        if (includeTcNativeWin64 != null) {
          aos.putArchiveEntry(new JarArchiveEntry("tcnative-1.dll.64"));
          Files.copy(Paths.get(includeTcNativeWin64), aos);
          aos.closeArchiveEntry();
        }

        String[] runnerClasses = {
          "ch.rasc.embeddedtc.runner.CheckConfig$CheckConfigOptions",
          "ch.rasc.embeddedtc.runner.CheckConfig",
          "ch.rasc.embeddedtc.runner.Config",
          "ch.rasc.embeddedtc.runner.Shutdown",
          "ch.rasc.embeddedtc.runner.Context",
          "ch.rasc.embeddedtc.runner.DeleteDirectory",
          "ch.rasc.embeddedtc.runner.ObfuscateUtil$ObfuscateOptions",
          "ch.rasc.embeddedtc.runner.ObfuscateUtil",
          "ch.rasc.embeddedtc.runner.Runner$1",
          "ch.rasc.embeddedtc.runner.Runner$2",
          "ch.rasc.embeddedtc.runner.Runner$StartOptions",
          "ch.rasc.embeddedtc.runner.Runner$StopOptions",
          "ch.rasc.embeddedtc.runner.Runner$RunnerShutdownHook",
          "ch.rasc.embeddedtc.runner.Runner"
        };

        for (String rc : runnerClasses) {
          String classAsPath = rc.replace('.', '/') + ".class";

          try (InputStream is = getClass().getResourceAsStream("/" + classAsPath)) {
            aos.putArchiveEntry(new JarArchiveEntry(classAsPath));
            IOUtils.copy(is, aos);
            aos.closeArchiveEntry();
          }
        }

        Manifest manifest = new Manifest();

        Manifest.Attribute mainClassAtt = new Manifest.Attribute();
        mainClassAtt.setName("Main-Class");
        mainClassAtt.setValue(Runner.class.getName());
        manifest.addConfiguredAttribute(mainClassAtt);

        aos.putArchiveEntry(new JarArchiveEntry("META-INF/MANIFEST.MF"));
        manifest.write(aos);
        aos.closeArchiveEntry();

        aos.putArchiveEntry(new JarArchiveEntry(Runner.TIMESTAMP_FILENAME));
        aos.write(String.valueOf(System.currentTimeMillis()).getBytes(StandardCharsets.UTF_8));
        aos.closeArchiveEntry();
      }
    } catch (IOException | ArchiveException | ManifestException e) {
      throw new MojoExecutionException(e.getMessage(), e);
    }
  }
  public void execute() throws MojoExecutionException, MojoFailureException {
    if (this.skip) {
      getLog().info("skip execution");
      return;
    }
    // project.addAttachedArtifact(  );
    File warExecFile = new File(buildDirectory, finalName);
    if (warExecFile.exists()) {
      warExecFile.delete();
    }

    File execWarJar = new File(buildDirectory, finalName);

    FileOutputStream execWarJarOutputStream = null;
    ArchiveOutputStream os = null;
    File tmpPropertiesFile = null;
    File tmpManifestFile = null;
    FileOutputStream tmpPropertiesFileOutputStream = null;
    PrintWriter tmpManifestWriter = null;

    try {

      tmpPropertiesFile = new File(buildDirectory, "war-exec.properties");
      if (tmpPropertiesFile.exists()) {
        tmpPropertiesFile.delete();
      }
      tmpPropertiesFile.getParentFile().mkdirs();

      tmpManifestFile = new File(buildDirectory, "war-exec.manifest");
      if (tmpManifestFile.exists()) {
        tmpManifestFile.delete();
      }
      tmpPropertiesFileOutputStream = new FileOutputStream(tmpPropertiesFile);
      execWarJar.getParentFile().mkdirs();
      execWarJar.createNewFile();
      execWarJarOutputStream = new FileOutputStream(execWarJar);

      tmpManifestWriter = new PrintWriter(tmpManifestFile);

      // store :
      // * wars in the root: foo.war
      // * tomcat jars
      // * file tomcat.standalone.properties with possible values :
      //   * useServerXml=true/false to use directly the one provided
      //   * enableNaming=true/false
      //   * wars=foo.war|contextpath;bar.war  ( |contextpath is optionnal if empty use the war name
      // )
      //   * accessLogValveFormat=
      //   * connectorhttpProtocol: HTTP/1.1 or org.apache.coyote.http11.Http11NioProtocol
      // * optionnal: conf/ with usual tomcat configuration files
      // * MANIFEST with Main-Class

      Properties properties = new Properties();

      properties.put(
          Tomcat7Runner.ARCHIVE_GENERATION_TIMESTAMP_KEY,
          Long.toString(System.currentTimeMillis()));
      properties.put(Tomcat7Runner.ENABLE_NAMING_KEY, Boolean.toString(enableNaming));
      properties.put(Tomcat7Runner.ACCESS_LOG_VALVE_FORMAT_KEY, accessLogValveFormat);
      properties.put(Tomcat7Runner.HTTP_PROTOCOL_KEY, connectorHttpProtocol);

      os =
          new ArchiveStreamFactory()
              .createArchiveOutputStream(ArchiveStreamFactory.JAR, execWarJarOutputStream);

      if ("war".equals(project.getPackaging())) {

        os.putArchiveEntry(new JarArchiveEntry(StringUtils.removeStart(path, "/") + ".war"));
        IOUtils.copy(new FileInputStream(projectArtifact.getFile()), os);
        os.closeArchiveEntry();

        properties.put(Tomcat7Runner.WARS_KEY, StringUtils.removeStart(path, "/") + ".war|" + path);
      } else if (warRunDependencies != null && !warRunDependencies.isEmpty()) {
        for (WarRunDependency warRunDependency : warRunDependencies) {
          if (warRunDependency.dependency != null) {
            Dependency dependency = warRunDependency.dependency;
            Artifact artifact =
                artifactFactory.createArtifactWithClassifier(
                    dependency.getGroupId(),
                    dependency.getArtifactId(),
                    dependency.getVersion(),
                    dependency.getType(),
                    dependency.getClassifier());

            artifactResolver.resolve(artifact, this.remoteRepos, this.local);

            File warFileToBundle = new File(resolvePluginWorkDir(), artifact.getFile().getName());
            FileUtils.copyFile(artifact.getFile(), warFileToBundle);

            if (warRunDependency.contextXml != null) {
              warFileToBundle = addContextXmlToWar(warRunDependency.contextXml, warFileToBundle);
            }
            final String warFileName = artifact.getFile().getName();
            os.putArchiveEntry(new JarArchiveEntry(warFileName));
            IOUtils.copy(new FileInputStream(warFileToBundle), os);
            os.closeArchiveEntry();
            String propertyWarValue = properties.getProperty(Tomcat7Runner.WARS_KEY);
            String contextPath =
                StringUtils.isEmpty(warRunDependency.contextPath)
                    ? "/"
                    : warRunDependency.contextPath;
            if (propertyWarValue != null) {
              properties.put(
                  Tomcat7Runner.WARS_KEY, propertyWarValue + ";" + warFileName + "|" + contextPath);
            } else {
              properties.put(Tomcat7Runner.WARS_KEY, warFileName + "|" + contextPath);
            }
          }
        }
      }

      if (serverXml != null && serverXml.exists()) {
        os.putArchiveEntry(new JarArchiveEntry("conf/server.xml"));
        IOUtils.copy(new FileInputStream(serverXml), os);
        os.closeArchiveEntry();
        properties.put(Tomcat7Runner.USE_SERVER_XML_KEY, Boolean.TRUE.toString());
      } else {
        properties.put(Tomcat7Runner.USE_SERVER_XML_KEY, Boolean.FALSE.toString());
      }

      os.putArchiveEntry(new JarArchiveEntry("conf/web.xml"));
      IOUtils.copy(getClass().getResourceAsStream("/conf/web.xml"), os);
      os.closeArchiveEntry();

      properties.store(tmpPropertiesFileOutputStream, "created by Apache Tomcat Maven plugin");

      tmpPropertiesFileOutputStream.flush();
      tmpPropertiesFileOutputStream.close();

      os.putArchiveEntry(new JarArchiveEntry(Tomcat7RunnerCli.STAND_ALONE_PROPERTIES_FILENAME));
      IOUtils.copy(new FileInputStream(tmpPropertiesFile), os);
      os.closeArchiveEntry();

      // add tomcat classes
      for (Artifact pluginArtifact : pluginArtifacts) {
        if (StringUtils.equals("org.apache.tomcat", pluginArtifact.getGroupId())
            || StringUtils.equals("org.apache.tomcat.embed", pluginArtifact.getGroupId())
            || StringUtils.equals("org.eclipse.jdt.core.compiler", pluginArtifact.getGroupId())
            || StringUtils.equals("commons-cli", pluginArtifact.getArtifactId())
            || StringUtils.equals("tomcat7-war-runner", pluginArtifact.getArtifactId())) {
          JarFile jarFile = new JarFile(pluginArtifact.getFile());
          extractJarToArchive(jarFile, os);
        }
      }

      // add extra dependencies
      if (extraDependencies != null && !extraDependencies.isEmpty()) {
        for (Dependency dependency : extraDependencies) {
          // String groupId, String artifactId, String version, String scope, String type
          Artifact artifact =
              artifactFactory.createArtifact(
                  dependency.getGroupId(),
                  dependency.getArtifactId(),
                  dependency.getVersion(),
                  dependency.getScope(),
                  dependency.getType());

          artifactResolver.resolve(artifact, this.remoteRepos, this.local);
          JarFile jarFile = new JarFile(artifact.getFile());
          extractJarToArchive(jarFile, os);
        }
      }

      Manifest manifest = new Manifest();

      Manifest.Attribute mainClassAtt = new Manifest.Attribute();
      mainClassAtt.setName("Main-Class");
      mainClassAtt.setValue(mainClass);
      manifest.addConfiguredAttribute(mainClassAtt);

      manifest.write(tmpManifestWriter);
      tmpManifestWriter.flush();
      tmpManifestWriter.close();

      os.putArchiveEntry(new JarArchiveEntry("META-INF/MANIFEST.MF"));
      IOUtils.copy(new FileInputStream(tmpManifestFile), os);
      os.closeArchiveEntry();

      if (attachArtifact) {
        // MavenProject project, String artifactType, String artifactClassifier, File artifactFile
        projectHelper.attachArtifact(
            project, attachArtifactClassifierType, attachArtifactClassifier, execWarJar);
      }

      if (extraResources != null) {
        for (ExtraResource extraResource : extraResources) {

          DirectoryScanner directoryScanner = new DirectoryScanner();
          directoryScanner.setBasedir(extraResource.getDirectory());
          directoryScanner.addDefaultExcludes();
          directoryScanner.setExcludes(toStringArray(extraResource.getExcludes()));
          directoryScanner.setIncludes(toStringArray(extraResource.getIncludes()));
          directoryScanner.scan();
          for (String includeFile : directoryScanner.getIncludedFiles()) {
            getLog().debug("include file:" + includeFile);
            os.putArchiveEntry(new JarArchiveEntry(includeFile));
            IOUtils.copy(
                new FileInputStream(new File(extraResource.getDirectory(), includeFile)), os);
            os.closeArchiveEntry();
          }
        }
      }

      if (tomcatConfigurationFilesDirectory != null && tomcatConfigurationFilesDirectory.exists()) {
        // Because its the tomcat default dir for configs
        String aConfigOutputDir = "conf/";
        copyDirectoryContentIntoArchive(tomcatConfigurationFilesDirectory, aConfigOutputDir, os);
      }

    } catch (ManifestException e) {
      throw new MojoExecutionException(e.getMessage(), e);
    } catch (IOException e) {
      throw new MojoExecutionException(e.getMessage(), e);
    } catch (ArchiveException e) {
      throw new MojoExecutionException(e.getMessage(), e);
    } catch (ArtifactNotFoundException e) {
      throw new MojoExecutionException(e.getMessage(), e);
    } catch (ArtifactResolutionException e) {
      throw new MojoExecutionException(e.getMessage(), e);
    } finally {
      IOUtils.closeQuietly(os);
      IOUtils.closeQuietly(tmpManifestWriter);
      IOUtils.closeQuietly(execWarJarOutputStream);
      IOUtils.closeQuietly(tmpPropertiesFileOutputStream);
    }
  }