-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3397 from ia3andy/fix-3388
Fix Deadlocks using CreateProject with multiple threads
- Loading branch information
Showing
16 changed files
with
385 additions
and
246 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,20 @@ | ||
package io.quarkus.cli.commands; | ||
|
||
import static io.quarkus.generators.ProjectGenerator.ADDITIONAL_GITIGNORE_ENTRIES; | ||
import static io.quarkus.generators.ProjectGenerator.CLASS_NAME; | ||
import static io.quarkus.generators.ProjectGenerator.PACKAGE_NAME; | ||
import static io.quarkus.generators.ProjectGenerator.PROJECT_ARTIFACT_ID; | ||
import static io.quarkus.generators.ProjectGenerator.PROJECT_GROUP_ID; | ||
import static io.quarkus.generators.ProjectGenerator.PROJECT_VERSION; | ||
import static io.quarkus.generators.ProjectGenerator.QUARKUS_VERSION; | ||
import static io.quarkus.generators.ProjectGenerator.SOURCE_TYPE; | ||
import static io.quarkus.maven.utilities.MojoUtils.QUARKUS_VERSION_PROPERTY; | ||
import static io.quarkus.maven.utilities.MojoUtils.configuration; | ||
import static io.quarkus.maven.utilities.MojoUtils.getBomArtifactId; | ||
import static io.quarkus.maven.utilities.MojoUtils.getPluginArtifactId; | ||
import static io.quarkus.maven.utilities.MojoUtils.getPluginGroupId; | ||
import static io.quarkus.maven.utilities.MojoUtils.getPluginVersion; | ||
import static io.quarkus.maven.utilities.MojoUtils.plugin; | ||
import static io.quarkus.templates.QuarkusTemplate.ADDITIONAL_GITIGNORE_ENTRIES; | ||
import static io.quarkus.templates.QuarkusTemplate.CLASS_NAME; | ||
import static io.quarkus.templates.QuarkusTemplate.PACKAGE_NAME; | ||
import static io.quarkus.templates.QuarkusTemplate.PROJECT_ARTIFACT_ID; | ||
import static io.quarkus.templates.QuarkusTemplate.PROJECT_GROUP_ID; | ||
import static io.quarkus.templates.QuarkusTemplate.PROJECT_VERSION; | ||
import static io.quarkus.templates.QuarkusTemplate.QUARKUS_VERSION; | ||
import static io.quarkus.templates.QuarkusTemplate.SOURCE_TYPE; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.ByteArrayOutputStream; | ||
|
@@ -38,12 +38,12 @@ | |
import org.apache.maven.model.Profile; | ||
|
||
import io.quarkus.cli.commands.writer.ProjectWriter; | ||
import io.quarkus.generators.BuildTool; | ||
import io.quarkus.generators.ProjectGeneratorRegistry; | ||
import io.quarkus.generators.SourceType; | ||
import io.quarkus.generators.rest.BasicRestProjectGenerator; | ||
import io.quarkus.maven.utilities.MojoUtils; | ||
import io.quarkus.maven.utilities.MojoUtils.Element; | ||
import io.quarkus.templates.BuildTool; | ||
import io.quarkus.templates.SourceType; | ||
import io.quarkus.templates.TemplateRegistry; | ||
import io.quarkus.templates.rest.BasicRest; | ||
|
||
/** | ||
* @author <a href="mailto:[email protected]">Ståle Pedersen</a> | ||
|
@@ -124,7 +124,7 @@ public boolean doCreateProject(final Map<String, Object> context) throws IOExcep | |
context.put(CLASS_NAME, className); | ||
} | ||
|
||
TemplateRegistry.createTemplateWith(BasicRest.TEMPLATE_NAME).generate(writer, context); | ||
ProjectGeneratorRegistry.get(BasicRestProjectGenerator.NAME).generate(writer, context); | ||
|
||
final byte[] pom = writer.getContent(POM_PATH); | ||
model = MojoUtils.readPom(new ByteArrayInputStream(pom)); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
.../java/io/quarkus/templates/BuildTool.java → ...java/io/quarkus/generators/BuildTool.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletions
4
...io/quarkus/templates/QuarkusTemplate.java → .../quarkus/generators/ProjectGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
devtools/common/src/main/java/io/quarkus/generators/ProjectGeneratorRegistry.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package io.quarkus.generators; | ||
|
||
import java.util.Map; | ||
import java.util.NoSuchElementException; | ||
import java.util.ServiceLoader; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
/** | ||
* @author <a href="[email protected]">Christophe Laprun</a> | ||
*/ | ||
public class ProjectGeneratorRegistry { | ||
|
||
private static final Map<String, ProjectGenerator> generators = new ConcurrentHashMap<>(7); | ||
private static final ProjectGeneratorRegistry INSTANCE = new ProjectGeneratorRegistry(); | ||
|
||
private ProjectGeneratorRegistry() { | ||
loadGenerators(); | ||
} | ||
|
||
public static ProjectGeneratorRegistry getInstance() { | ||
return INSTANCE; | ||
} | ||
|
||
public static ProjectGenerator get(String name) throws NoSuchElementException { | ||
final ProjectGenerator generator = generators.get(name); | ||
if (generator == null) { | ||
throw new NoSuchElementException("Unknown generator: " + name); | ||
} | ||
|
||
return generator; | ||
} | ||
|
||
private static void register(ProjectGenerator generator) { | ||
if (generator != null) { | ||
generators.put(generator.getName(), generator); | ||
} else { | ||
throw new NullPointerException("Cannot register null generator"); | ||
} | ||
} | ||
|
||
private static void loadGenerators() { | ||
ServiceLoader<ProjectGenerator> serviceLoader = ServiceLoader.load(ProjectGenerator.class); | ||
serviceLoader.iterator().forEachRemaining(ProjectGeneratorRegistry::register); | ||
} | ||
} |
2 changes: 1 addition & 1 deletion
2
...java/io/quarkus/templates/SourceType.java → ...ava/io/quarkus/generators/SourceType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
package io.quarkus.templates; | ||
package io.quarkus.generators; | ||
|
||
import io.quarkus.maven.utilities.MojoUtils; | ||
|
||
|
171 changes: 171 additions & 0 deletions
171
devtools/common/src/main/java/io/quarkus/generators/rest/BasicRestProjectGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
package io.quarkus.generators.rest; | ||
|
||
import static java.lang.String.format; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.ByteArrayInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStreamReader; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.Map; | ||
import java.util.Map.Entry; | ||
import java.util.stream.Collectors; | ||
|
||
import org.apache.maven.model.Model; | ||
|
||
import io.quarkus.cli.commands.writer.ProjectWriter; | ||
import io.quarkus.generators.ProjectGenerator; | ||
import io.quarkus.generators.SourceType; | ||
import io.quarkus.maven.utilities.MojoUtils; | ||
|
||
public class BasicRestProjectGenerator implements ProjectGenerator { | ||
|
||
public static final String NAME = "basic-rest"; | ||
|
||
public BasicRestProjectGenerator() { | ||
} | ||
|
||
@Override | ||
public String getName() { | ||
return NAME; | ||
} | ||
|
||
@Override | ||
public void generate(final ProjectWriter writer, Map<String, Object> parameters) throws IOException { | ||
final BasicRestProject project = new BasicRestProject(writer, parameters); | ||
|
||
project.initProject(); | ||
project.setupContext(); | ||
|
||
project.createClasses(); | ||
|
||
project.createIndexPage(); | ||
project.createDockerFiles(); | ||
project.createDockerIgnore(); | ||
project.createApplicationConfig(); | ||
|
||
project.createGitIgnore(); | ||
} | ||
|
||
private class BasicRestProject { | ||
private Map<String, Object> context; | ||
private String path = "/hello"; | ||
private ProjectWriter writer; | ||
private String srcMainPath; | ||
private String testMainPath; | ||
private SourceType type; | ||
|
||
private BasicRestProject(final ProjectWriter writer, final Map<String, Object> parameters) { | ||
this.writer = writer; | ||
this.context = parameters; | ||
this.type = (SourceType) context.get(SOURCE_TYPE); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
private <T> T get(final String key, final String defaultValue) { | ||
return (T) context.getOrDefault(key, defaultValue); | ||
} | ||
|
||
private boolean initProject() throws IOException { | ||
boolean newProject = !writer.exists("pom.xml"); | ||
if (newProject) { | ||
generate(type.getPomResourceTemplate(getName()), context, "pom.xml", "pom.xml"); | ||
} else { | ||
final Model model = MojoUtils.readPom(new ByteArrayInputStream(writer.getContent("pom.xml"))); | ||
context.put(PROJECT_GROUP_ID, model.getGroupId()); | ||
context.put(PROJECT_ARTIFACT_ID, model.getArtifactId()); | ||
} | ||
|
||
path = get(RESOURCE_PATH, path); | ||
|
||
srcMainPath = writer.mkdirs(type.getSrcDir()); | ||
testMainPath = writer.mkdirs(type.getTestSrcDir()); | ||
|
||
return newProject; | ||
} | ||
|
||
private void generate(final String templateName, final Map<String, Object> context, final String outputFilePath, | ||
final String resourceType) | ||
throws IOException { | ||
if (!writer.exists(outputFilePath)) { | ||
String path = templateName.startsWith("/") ? templateName : "/" + templateName; | ||
try (final BufferedReader stream = new BufferedReader( | ||
new InputStreamReader(getClass().getResourceAsStream(path), StandardCharsets.UTF_8))) { | ||
String template = stream.lines().collect(Collectors.joining("\n")); | ||
for (Entry<String, Object> e : context.entrySet()) { | ||
if (e.getValue() != null) { // Exclude null values (classname and path can be null) | ||
template = template.replace(format("${%s}", e.getKey()), e.getValue().toString()); | ||
} | ||
} | ||
writer.write(outputFilePath, template); | ||
} | ||
} | ||
} | ||
|
||
private void createIndexPage() throws IOException { | ||
// Generate index page | ||
String resources = "src/main/resources/META-INF/resources"; | ||
String index = writer.mkdirs(resources) + "/index.html"; | ||
if (!writer.exists(index)) { | ||
generate("templates/index.ftl", context, index, "welcome page"); | ||
} | ||
|
||
} | ||
|
||
private void createDockerFiles() throws IOException { | ||
String dockerRoot = "src/main/docker"; | ||
String dockerRootDir = writer.mkdirs(dockerRoot); | ||
generate("templates/dockerfile-native.ftl", context, dockerRootDir + "/Dockerfile.native", | ||
"native docker file"); | ||
generate("templates/dockerfile-jvm.ftl", context, dockerRootDir + "/Dockerfile.jvm", "jvm docker file"); | ||
} | ||
|
||
private void createDockerIgnore() throws IOException { | ||
String docker = writer.mkdirs("") + ".dockerignore"; | ||
generate("templates/dockerignore.ftl", context, docker, "docker ignore"); | ||
} | ||
|
||
private void createGitIgnore() throws IOException { | ||
String gitignore = writer.mkdirs("") + ".gitignore"; | ||
generate("templates/gitignore.ftl", context, gitignore, "git ignore"); | ||
} | ||
|
||
private void createApplicationConfig() throws IOException { | ||
String meta = "src/main/resources"; | ||
String file = writer.mkdirs(meta) + "/application.properties"; | ||
if (!writer.exists(file)) { | ||
writer.write(file, "# Configuration file" + System.lineSeparator() + "# key = value"); | ||
} | ||
} | ||
|
||
private void setupContext() throws IOException { | ||
if (context.get(CLASS_NAME) != null) { | ||
String packageName = (String) context.get(PACKAGE_NAME); | ||
|
||
if (packageName != null) { | ||
String packageDir = srcMainPath + '/' + packageName.replace('.', '/'); | ||
String testPackageDir = testMainPath + '/' + packageName.replace('.', '/'); | ||
srcMainPath = writer.mkdirs(packageDir); | ||
testMainPath = writer.mkdirs(testPackageDir); | ||
} else { | ||
throw new NullPointerException("Need a non-null package name"); | ||
} | ||
} | ||
} | ||
|
||
private void createClasses() throws IOException { | ||
Object className = context.get(CLASS_NAME); | ||
// If className is null we disable the generation of the JAX-RS resource. | ||
if (className != null) { | ||
String extension = type.getExtension(); | ||
String classFile = srcMainPath + '/' + className + extension; | ||
String testClassFile = testMainPath + '/' + className + "Test" + extension; | ||
String itTestClassFile = testMainPath + '/' + "Native" + className + "IT" + extension; | ||
String name = getName(); | ||
generate(type.getSrcResourceTemplate(name), context, classFile, "resource code"); | ||
generate(type.getTestResourceTemplate(name), context, testClassFile, "test code"); | ||
generate(type.getNativeTestResourceTemplate(name), context, itTestClassFile, "IT code"); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.