Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vlingo-schemata pull/push schema mojos #2

Merged
merged 9 commits into from
Dec 15, 2019
12 changes: 12 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
<organization>Dmitry Ledentsov</organization>
<organizationUrl>https://github.com/d-led</organizationUrl>
</developer>
<developer>
<name>Wolfgang Werner</name>
<email>wolfgang.werner@gmail.com</email>
<organization>Wolfgang Werner</organization>
<organizationUrl>https://wolfgang-werner.net</organizationUrl>
</developer>
</developers>
<scm>
<connection>scm:git:git://github.com/vlingo/vlingo-build-plugins.git</connection>
Expand Down Expand Up @@ -112,6 +118,12 @@
<version>1.0.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>3.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
<distributionManagement>
<repository>
Expand Down
136 changes: 136 additions & 0 deletions src/main/java/io/vlingo/maven/schemata/PullSchemataMojo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright © 2012-2018 Vaughn Vernon. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain
// one at https://mozilla.org/MPL/2.0/.

package io.vlingo.maven.schemata;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Mojo(name = "pull-schemata", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
public class PullSchemataMojo extends AbstractMojo {

public static final String SCHEMATA_CODE_RESOURCE_PATH = "/code/%s/%s";
public static final String SCHEMATA_REFERENCE_SEPARATOR = ":";
Pattern PACKAGE_NAME_PATTERN = Pattern.compile("package (.+);.*");


@Parameter(readonly = true, defaultValue = "${project}")
private MavenProject project;

@Parameter(name = "schemataService")
private SchemataService schemataService;

@Parameter(name = "outputDirectory", defaultValue = "target/generated-sources/vlingo", required = true)
private File outputDirectory;

@Parameter(property = "schemata")
private List<Schema> schemata;

private final io.vlingo.actors.Logger logger;

public PullSchemataMojo() {
this.logger = io.vlingo.actors.Logger.basicLogger();
logger.info("vlingo/maven: Pulling code generated from vlingo/schemata registry.");
}

@Override
public void execute() throws MojoExecutionException {
logger.info(schemataService.toString());
this.project.addCompileSourceRoot(this.outputDirectory.toString());
try {
for (Schema schema : this.schemata) {
String reference = schema.getRef();
String source = this.pullSource(reference);
this.writeSourceFile(reference, source);
}
} catch (IOException e) {
throw new MojoExecutionException("Pulling schemata failed", e);
}
}

private String pullSource(String schemaReference) throws IOException {
URL codeResourceUrl = codeResourceUrl(this.schemataService.getUrl(), schemaReference, "java");

logger.info("Pulling {} from {}", schemaReference, codeResourceUrl);
URLConnection connection = codeResourceUrl.openConnection();
connection.setRequestProperty("Accept", "text/plain, text/x-java-source");

StringBuilder sources = new StringBuilder();
try (BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream()))) {
String line;
while ((line = in.readLine()) != null) {
sources.append(line);
sources.append("\n");
}
}
logger.info("Pulled {}", schemaReference);
return sources.toString();
}

private void writeSourceFile(String schemaReference, String source) throws IOException {

// we need to parse the sources as we can't access event type meta data here
Path sourceDirPath = packagePathFromSource(this.outputDirectory, source);
Files.createDirectories(sourceDirPath);
Path sourceFilePath = sourceDirPath.resolve(fileNameFromReference(schemaReference) + ".java");

logger.info("Writing {} to {}", schemaReference, sourceFilePath);
Files.write(
sourceFilePath,
source.getBytes(StandardCharsets.UTF_8),
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
logger.info("Wrote {}", sourceFilePath);

}

Path packagePathFromSource(File srcRoot, String source) {
Matcher matcher = PACKAGE_NAME_PATTERN.matcher(source);
boolean isInDefaultPackage = !matcher.find();
if (isInDefaultPackage) {
return srcRoot.toPath();
}

String packageName = matcher.group(1);
String[] directories = packageName.split("\\.");
String relativePackagePath = String.join(File.separator, directories);
return srcRoot.toPath().resolve(relativePackagePath);
}

private String fileNameFromReference(String reference) {
String[] parts = reference.split(SCHEMATA_REFERENCE_SEPARATOR);
if (parts.length < 4) {
throw new IllegalArgumentException("Pass a reference in the form of <organization>:<unit>:<context>:<schema>[:<version>]");
}
return parts[3];
}

private URL codeResourceUrl(URL baseUrl, String schemaReference, String language) throws MalformedURLException {
return new URL(baseUrl, String.format(SCHEMATA_CODE_RESOURCE_PATH, schemaReference, language));
}
}
149 changes: 149 additions & 0 deletions src/main/java/io/vlingo/maven/schemata/PushSchemataMojo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Copyright © 2012-2018 Vaughn Vernon. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain
// one at https://mozilla.org/MPL/2.0/.

package io.vlingo.maven.schemata;

import com.google.gson.Gson;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.List;


@Mojo(name = "push-schemata", defaultPhase = LifecyclePhase.INSTALL)
public class PushSchemataMojo extends AbstractMojo {
public static final String SCHEMATA_VERSION_RESOURCE_PATH = "/versions/%s";
private final Gson gson;


@Parameter(readonly = true, defaultValue = "${project}")
private MavenProject project;

@Parameter(name = "schemataService")
private SchemataService schemataService;


@Parameter(property = "schemata")
private List<Schema> schemata;

private final io.vlingo.actors.Logger logger;

public PushSchemataMojo() {
this.logger = io.vlingo.actors.Logger.basicLogger();
logger.info("vlingo/maven: Pushing project schemata to vlingo-schemata registry.");
gson = new Gson();
}

@Override
public void execute() throws MojoExecutionException {

for (Schema schema : this.schemata) {
String reference = schema.getRef();
File sourceFile = schema.getSrc();
String description = this.generateDescription(reference, this.project.getArtifact().toString());

try {
String specification = new String(Files.readAllBytes(sourceFile.toPath()));
String previousVersion = schema.getPreviousVersion() == null ? "0.0.0" : schema.getPreviousVersion();

String payload = this.payloadFrom(specification, previousVersion, description);
this.push(reference, payload);
} catch (IOException e) {
throw new MojoExecutionException(
"Schema specification " + sourceFile.getAbsolutePath() +
" could not be pushed to " + schemataService.getUrl()
, e);
}
}

}

private String generateDescription(String reference, String project) {
StringBuilder description = new StringBuilder();
description.append("# ");
description.append(reference);
description.append("\n\n");
description.append("Schema `");
description.append(reference);
description.append("` pushed from `");
description.append(project);
description.append("`.\n\n");
description.append("Publication date: ");
description.append(LocalDateTime.now().toString());

return description.toString();
}

private String payloadFrom(String specification, String previousVersion, String description) {
SchemaVersion payload = new SchemaVersion(description, specification, previousVersion);
return gson.toJson(payload);
}

private void push(String reference, String payload) throws IOException, MojoExecutionException {
URL schemaVersionUrl = schemaVersionUrl(this.schemataService.getUrl(), reference);

logger.info("Pushing {} to {}.", reference, schemaVersionUrl);

HttpURLConnection connection = (HttpURLConnection) schemaVersionUrl.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");

OutputStream os = connection.getOutputStream();
os.write(payload.getBytes(StandardCharsets.UTF_8));
os.close();

StringBuilder sb = new StringBuilder();
int HttpResult = connection.getResponseCode();
if (HttpResult == HttpURLConnection.HTTP_CREATED) {
logger.info("Successfully pushed {}", schemaVersionUrl);
} else {
try(BufferedReader br = new BufferedReader(
new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
StringBuilder response = new StringBuilder();
String responseLine = null;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
logger.error("Pushing the schema version failed: {}", response.toString());
}
throw new MojoExecutionException(
"Could not push " + reference
+ " to " + schemaVersionUrl
+ ": " + connection.getResponseMessage()
+ " - " + connection.getResponseCode());
}
}

private URL schemaVersionUrl(URL baseUrl, String schemaVersionReference) throws MalformedURLException {
return new URL(baseUrl, String.format(SCHEMATA_VERSION_RESOURCE_PATH, schemaVersionReference));
}


private class SchemaVersion {
final String description;
final String specification;
final String previousVersion;

private SchemaVersion(String description, String specification, String previousVersion) {
this.description = description;
this.specification = specification;
this.previousVersion = previousVersion;
}
}
}
49 changes: 49 additions & 0 deletions src/main/java/io/vlingo/maven/schemata/Schema.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package io.vlingo.maven.schemata;

import org.apache.maven.plugins.annotations.Parameter;

import java.io.File;

public class Schema {
@Parameter(property = "src")
private File src;

@Parameter(property = "ref", required = true)
private String ref;

@Parameter(property = "previousVersion")
private String previousVersion;

public File getSrc() {
return src;
}

public void setSrc(File src) {
this.src = src;
}

public String getRef() {
return ref;
}

public void setRef(String ref) {
this.ref = ref;
}

public String getPreviousVersion() {
return previousVersion;
}

public void setPreviousVersion(String previousVersion) {
this.previousVersion = previousVersion;
}

@Override
public String toString() {
return "Schema{" +
"src=" + src +
", ref='" + ref + '\'' +
", previousVersion='" + previousVersion + '\'' +
'}';
}
}
Loading