All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.graphwalker.maven.plugin.WatchMojo Maven / Gradle / Ivy

package org.graphwalker.maven.plugin;

/*
 * #%L
 * GraphWalker Maven Plugin
 * %%
 * Copyright (C) 2005 - 2014 GraphWalker
 * %%
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * #L%
 */

import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
import org.graphwalker.io.factory.ContextFactory;
import org.graphwalker.io.factory.ContextFactoryScanner;
import org.graphwalker.java.source.CodeGenerator;
import org.graphwalker.java.source.SourceFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static com.sun.nio.file.SensitivityWatchEventModifier.HIGH;
import static java.nio.file.StandardWatchEventKinds.*;
import static org.graphwalker.core.model.Model.RuntimeModel;

/**
 * @author Nils Olsson
 */
@Mojo(name = "watch")
public final class WatchMojo extends AbstractMojo {

  private static final WatchEvent.Kind[] EVENT_TYPES = new WatchEvent.Kind[]{ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY};

  @Component
  private MavenProject mavenProject;

  @Parameter(defaultValue = "${project.build.sourceEncoding}")
  private String encoding;

  @Parameter(defaultValue = "${project.build.directory}/generated-sources/graphwalker")
  private File sourcesDirectory;

  @Parameter(defaultValue = "${project.build.directory}/generated-test-sources/graphwalker")
  private File testSourcesDirectory;

  @SuppressWarnings("unchecked")
  private static  WatchEvent cast(WatchEvent event) {
    return (WatchEvent) event;
  }

  private WatchService watchService;
  private final CodeGenerator codeGenerator = new CodeGenerator();
  private final Map resourceMap = new HashMap<>();
  private final Map watchKeyMap = new HashMap<>();

  private String getEncoding() {
    return StringUtils.isEmpty(encoding) ? ReaderFactory.FILE_ENCODING : encoding;
  }

  @Override
  public void execute() throws MojoExecutionException, MojoFailureException {
    try {
      addResources(mavenProject.getResources(), sourcesDirectory);
      addResources(mavenProject.getTestResources(), testSourcesDirectory);
      watch(resourceMap.keySet());
      //noinspection InfiniteLoopStatement
      for (; ; ) {
        WatchKey watchKey = getWatchService().take();
        Path path = watchKeyMap.get(watchKey);
        if (null == path) {
          continue;
        }
        for (WatchEvent event : watchKey.pollEvents()) {
          WatchEvent.Kind kind = event.kind();
          if (kind == OVERFLOW) {
            continue;
          }
          WatchEvent file = cast(event);
          Path resolvedPath = path.resolve(file.context());
          if (ENTRY_CREATE == event.kind() || ENTRY_MODIFY == event.kind()) {
            update(getRootPath(resolvedPath), resolvedPath);
          } else if (ENTRY_DELETE == event.kind()) {
            delete(getRootPath(resolvedPath), resolvedPath);
          }
        }
        watchKey.reset();
      }
    } catch (Exception e) {
      e.printStackTrace();
      throw new MojoExecutionException("", e);
    }
  }

  private void addResources(List resources, File outputDirectory) {
    for (Resource resource : resources) {
      resourceMap.put(FileSystems.getDefault().getPath(resource.getDirectory()), outputDirectory);
    }
  }

  private WatchService getWatchService() throws IOException {
    if (null == watchService) {
      watchService = FileSystems.getDefault().newWatchService();
    }
    return watchService;
  }

  private void watch(Set paths) throws IOException {
    for (Path path : paths) {
      watch(path);
    }
  }

  private void watch(Path path) throws IOException {
    if (Files.exists(path) && !watchKeyMap.values().contains(path)) {
      if (Files.isDirectory(path)) {
        WatchKey watchKey = path.register(getWatchService(), EVENT_TYPES, HIGH);
        watchKeyMap.put(watchKey, path);
        getLog().info("Watching: " + path.toString());
        Files.walkFileTree(path, new SimpleFileVisitor() {
          @Override
          public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attributes) throws IOException {
            watch(path);
            return FileVisitResult.CONTINUE;
          }
        });
      }
    }
  }

  private Path getRootPath(Path path) throws MojoExecutionException {
    for (Path rootPath : resourceMap.keySet()) {
      if (path.startsWith(rootPath)) {
        return rootPath;
      }
    }
    throw new MojoExecutionException("Path not found");
  }

  private boolean isModified(Path outputPath, Path path) throws IOException {
    return Files.getLastModifiedTime(outputPath).to(TimeUnit.MILLISECONDS)
      < Files.getLastModifiedTime(path).to(TimeUnit.MILLISECONDS);
  }

  private boolean isSupportedFileType(Path path) throws IOException {
    return null != ContextFactoryScanner.get(path);
  }

  private void generate(SourceFile sourceFile) {
    File outputFile = sourceFile.getOutputPath().toFile();
    try {
      ContextFactory contextFactory = ContextFactoryScanner.get(sourceFile.getInputPath());
      RuntimeModel model = contextFactory.create(sourceFile.getInputPath()).getModel();
      String source = codeGenerator.generate(sourceFile, model);
      if (Files.exists(sourceFile.getOutputPath())) {
        String existingSource = StringUtils.removeDuplicateWhitespace(FileUtils.fileRead(outputFile, getEncoding()));
        if (existingSource.equals(StringUtils.removeDuplicateWhitespace(new String(source.getBytes(), getEncoding())))) {
          return;
        }
      }
      if (getLog().isInfoEnabled()) {
        getLog().info("Generate: " + sourceFile.getOutputPath());
      }
      FileUtils.mkdir(sourceFile.getOutputPath().getParent().toFile().getAbsolutePath());
      FileUtils.fileDelete(outputFile.getAbsolutePath());
      FileUtils.fileWrite(outputFile.getAbsolutePath(), getEncoding(), source);
    } catch (Throwable t) {
      if (getLog().isInfoEnabled()) {
        getLog().info("Error: Generate: " + sourceFile.getOutputPath());
      }
      if (getLog().isDebugEnabled()) {
        getLog().debug("Error: Generate: " + sourceFile.getOutputPath(), t);
      }
    }
  }

  private void update(Path root, Path path) throws IOException {
    if (Files.exists(path) && !Files.isHidden(path)) {
      if (Files.isDirectory(path)) {
        watch(path);
      } else if (isSupportedFileType(path)) {
        SourceFile sourceFile = new SourceFile(path, root, resourceMap.get(root).toPath());
        if (!Files.exists(sourceFile.getOutputPath()) || isModified(sourceFile.getOutputPath(), path)) {
          generate(sourceFile);
        }
      }
    }
  }

  private void delete(Path root, Path path) throws IOException {
    if (isSupportedFileType(path)) {
      SourceFile sourceFile = new SourceFile(path, root, resourceMap.get(root).toPath());
      if (Files.exists(sourceFile.getOutputPath())) {
        Files.delete(sourceFile.getOutputPath());
        if (!Files.exists(sourceFile.getOutputPath())) {
          getLog().info("Delete: " + sourceFile.getOutputPath());
        }
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy