/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.jooby.run; import java.io.File; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.gradle.api.Project; import org.gradle.api.internal.ConventionTask; import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.TaskAction; import org.gradle.tooling.GradleConnector; import org.gradle.tooling.ProjectConnection; public class JoobyTask extends ConventionTask { private static final Object LOCK = new Object(); private static final List<String> XML_PROPS = Arrays.asList( "javax.xml.parsers.DocumentBuilderFactory", "javax.xml.parsers.SAXParserFactory", "javax.xml.stream.XMLInputFactory", "javax.xml.stream.XMLEventFactory", "javax.xml.transform.TransformerFactory", "javax.xml.stream.XMLOutputFactory", "javax.xml.datatype.DatatypeFactory", "org.xml.sax.driver"); private List<String> includes; private List<String> excludes; private String logLevel; private boolean block; private Set<File> classpath; private Set<File> src; private List<String> watchDirs; private String mainClassName; private String compiler; @TaskAction public void run() throws Exception { System.setProperty("logLevel", getLogLevel()); Project project = getProject(); String mId = project.getName(); List<File> cp = new ArrayList<>(); // conf & public getClasspath().forEach(cp::add); Main app = new Main(mId, getMainClassName(), toFiles(watchDirs), cp.toArray(new File[cp.size()])); if (includes != null) { app.includes(includes.stream().collect(Collectors.joining(File.pathSeparator))); } if (excludes != null) { app.excludes(excludes.stream().collect(Collectors.joining(File.pathSeparator))); } String compiler = getCompiler(); getLogger().info("compiler is {}", compiler); if ("on".equalsIgnoreCase(compiler)) { Path[] watchDirs = getSrc().stream() .map(File::toPath) .collect(Collectors.toList()) .toArray(new Path[0]); // don't start watcher if continuous is ON new Watcher((k, path) -> { if (path.toString().endsWith(".java")) { runTask(project, path, "classes"); } else if (path.toString().endsWith(".conf") || path.toString().endsWith(".properties")) { runTask(project, path, "classes"); } }, watchDirs).start(); } String[] args = project.getGradle().getStartParameter().getProjectProperties() .entrySet().stream().map(e -> e.toString()).collect(Collectors.toList()) .toArray(new String[0]); app.run(isBlock(), args); } private List<File> toFiles(final List<String> watchDirs) { List<File> files = new ArrayList<>(); if (watchDirs != null) { watchDirs.forEach(f -> files.add(new File(f))); } return files; } private void runTask(final Project project, final Path path, final String task) { synchronized (LOCK) { ProjectConnection connection = null; Map<String, String> xml = new HashMap<>(); try { // clean jaxp XML_PROPS.forEach(p -> xml.put(p, (String) System.getProperties().remove(p))); connection = GradleConnector.newConnector() .useInstallation(project.getGradle().getGradleHomeDir()) .forProjectDirectory(project.getRootDir()) .connect(); try { connection.newBuild() .setStandardError(System.err) .setStandardOutput(System.out) .forTasks(task) .run(); } catch (Exception ex) { getLogger().debug("Execution of " + task + " resulted in exception", ex); } } finally { // restore jaxp xml.forEach((k, v) -> { if (v != null) { System.setProperty(k, v); } }); if (connection != null) { connection.close(); } } } } public void setIncludes(final List<String> includes) { this.includes = includes; } public List<String> getIncludes() { return includes; } public void setExcludes(final List<String> excludes) { this.excludes = excludes; } public List<String> getExcludes() { return excludes; } public void setLogLevel(final String logLevel) { this.logLevel = logLevel; } public String getLogLevel() { return logLevel; } @InputFiles public Set<File> getClasspath() { return classpath; } public void setClasspath(final Set<File> classpath) { this.classpath = classpath; } public void setBlock(final boolean block) { this.block = block; } public boolean isBlock() { return block; } public String getMainClassName() { return mainClassName; } public void setMainClassName(final String mainClassName) { this.mainClassName = mainClassName; } public Set<File> getSrc() { return src; } public void setSrc(final Set<File> watchDirs) { this.src = watchDirs; } public List<String> getWatchDirs() { return watchDirs; } public void setWatchDirs(final List<String> watchDirs) { this.watchDirs = watchDirs; } public String getCompiler() { return compiler; } public void setCompiler(final String compiler) { this.compiler = compiler; } }