From 0cd203c32de2c7913c46764dbf319510f3723b60 Mon Sep 17 00:00:00 2001 From: Clebert Suconic Date: Fri, 29 Jul 2022 15:53:30 -0400 Subject: [PATCH] ARTEMIS-3914 Document client classpath automated --- artemis-maven-plugin/pom.xml | 8 +- .../artemis/maven/ArtemisAbstractPlugin.java | 15 +- .../maven/ArtemisDependencyDocPlugin.java | 257 ++++++++++++++++++ artemis-website/pom.xml | 79 ++++++ docs/user-manual/en/SUMMARY.md | 2 + .../en/client-classpath-jakarta.md | 1 + docs/user-manual/en/client-classpath-jms.md | 1 + docs/user-manual/en/client-classpath.md | 56 +++- 8 files changed, 408 insertions(+), 11 deletions(-) create mode 100644 artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ArtemisDependencyDocPlugin.java create mode 100644 docs/user-manual/en/client-classpath-jakarta.md create mode 100644 docs/user-manual/en/client-classpath-jms.md diff --git a/artemis-maven-plugin/pom.xml b/artemis-maven-plugin/pom.xml index 259cc0a3de..b54f32b9d9 100644 --- a/artemis-maven-plugin/pom.xml +++ b/artemis-maven-plugin/pom.xml @@ -40,17 +40,17 @@ org.apache.maven maven-artifact - 3.8.2 + 3.8.5 org.apache.maven maven-project - 2.0.8 + 2.2.1 org.eclipse.aether aether-api - 1.0.2.v20150114 + 1.1.0 org.apache.activemq @@ -75,7 +75,7 @@ org.apache.maven.plugin-tools maven-plugin-annotations - 3.4 + 3.6.4 provided diff --git a/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ArtemisAbstractPlugin.java b/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ArtemisAbstractPlugin.java index 6668ff1a45..37803612e9 100644 --- a/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ArtemisAbstractPlugin.java +++ b/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ArtemisAbstractPlugin.java @@ -102,7 +102,13 @@ public abstract class ArtemisAbstractPlugin extends AbstractMojo { return artifact; } - protected File resolveArtifact(Artifact artifact) throws MojoExecutionException, DependencyCollectionException { + protected File resolveArtifactFile(Artifact artifact) throws MojoExecutionException, DependencyCollectionException { + ArtifactResult result = resolveArtifact(artifact); + + return result.getArtifact().getFile(); + } + + protected ArtifactResult resolveArtifact(Artifact artifact) throws MojoExecutionException { ArtifactRequest request = new ArtifactRequest(); request.setArtifact(artifact); request.setRepositories(remoteRepos); @@ -113,8 +119,7 @@ public abstract class ArtemisAbstractPlugin extends AbstractMojo { } catch (ArtifactResolutionException e) { throw new MojoExecutionException(e.getMessage(), e); } - - return result.getArtifact().getFile(); + return result; } protected List explodeDependencies(Artifact artifact) throws DependencyCollectionException { @@ -164,7 +169,7 @@ public abstract class ArtemisAbstractPlugin extends AbstractMojo { List artifactsList = explodeDependencies(newArtifact(lib)); for (Artifact artifact : artifactsList) { - File artifactFile = resolveArtifact(artifact); + File artifactFile = resolveArtifactFile(artifact); filesSet.add(artifactFile); } } @@ -174,7 +179,7 @@ public abstract class ArtemisAbstractPlugin extends AbstractMojo { for (String lib : individualListParameter) { Artifact artifact = newArtifact(lib); getLog().debug("Single dpendency resolved::" + artifact); - File artifactFile = resolveArtifact(artifact); + File artifactFile = resolveArtifactFile(artifact); filesSet.add(artifactFile); } } diff --git a/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ArtemisDependencyDocPlugin.java b/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ArtemisDependencyDocPlugin.java new file mode 100644 index 0000000000..2dc5b869d3 --- /dev/null +++ b/artemis-maven-plugin/src/main/java/org/apache/activemq/artemis/maven/ArtemisDependencyDocPlugin.java @@ -0,0 +1,257 @@ +/* + * 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.apache.activemq.artemis.maven; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.maven.plugin.descriptor.PluginDescriptor; +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 org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.ArtifactResult; + +/** The following substitutions are made for each line + * X{group} with the groupID + * X{artifact} with the artifactID + * X{version} with the version + * X{classifier} with the classifier of the component + * X{package} a combination of the maven group:artifact:classifier + * X{url} with the url + * X{file} with the fileName + * X{fileMD} with the fileName on a LINK with MD style + * X{URI} with the URI + * X{detail} with the detail provided in the config */ +@Mojo(name = "dependency-doc", defaultPhase = LifecyclePhase.VERIFY) +public class ArtemisDependencyDocPlugin extends ArtemisAbstractPlugin { + + @Parameter + String name; + + /** + * The plugin descriptor + */ + private PluginDescriptor descriptor; + + @Parameter + private String[] groupOrder; + + @Parameter(defaultValue = "https://repo.maven.apache.org/maven2") + private String defaultRepo = "https://repo.maven.apache.org/maven2"; + + @Parameter + private String header; + + @Parameter + private String lib; + + @Parameter + private String line; + + @Parameter + private String footer; + + @Parameter + private String[] detailKey; + + @Parameter String[] detailValue; + + @Parameter + private String[] extraRepositories; + + @Parameter + private String file; + + private MavenProject project; + + @Override + protected boolean isIgnore() { + return false; + } + + + private String applyFilters(String content, Map filters) throws IOException { + + if (filters != null) { + for (Map.Entry entry : filters.entrySet()) { + try { + content = replace(content, entry.getKey(), entry.getValue()); + } catch (Throwable e) { + System.out.println("Error on " + entry.getKey()); + e.printStackTrace(); + } + } + } + return content; + } + + + private String replace(String content, String key, String value) { + return content.replaceAll(Pattern.quote(key), Matcher.quoteReplacement(value)); + } + + private String getPackageName(org.eclipse.aether.artifact.Artifact artifact) { + return artifact.getGroupId() + ":" + artifact.getArtifactId() + (artifact.getClassifier() != null && !artifact.getClassifier().equals("") ? ":" + artifact.getClassifier() : ""); + } + + private String getGroupOrder(String group) { + if (groupOrder == null) { + groupOrder = new String[] {"org.apache.activemq"}; + } + + int i = 0; + for (; i < groupOrder.length; i++) { + if (group.equals(groupOrder[i])) { + return Integer.toString(i); + } + } + return Integer.toString(i); + } + + @Override + protected void doExecute() { + + HashMap keys = new HashMap<>(); + + if (detailKey != null) { + if (detailValue == null) { + throw new IllegalStateException("you need to specify all detail parameters"); + } + + if (detailKey.length != detailValue.length) { + throw new IllegalStateException("Illegal argument size"); + } + + for (int i = 0; i < detailKey.length; i++) { + keys.put(detailKey[i], detailValue[i]); + } + } + + if (file == null) { + throw new IllegalStateException("you must specify the file output"); + } + + if (line == null) { + throw new IllegalStateException("you must specify the line"); + } + + + try { + File javaFile = new File(file); + javaFile.getParentFile().mkdirs(); + + PrintStream stream = new PrintStream(new BufferedOutputStream(new FileOutputStream(file))); + + if (header != null) { + stream.println(header); + } + + List artifacts = explodeDependencies(newArtifact(lib)); + + Collections.sort(artifacts, new Comparator() { + @Override + public int compare(Artifact o1, Artifact o2) { + String pref1 = getGroupOrder(o1.getGroupId()); + String pref2 = getGroupOrder(o2.getGroupId()); + return (pref1 + o1.getGroupId() + o1.getArtifactId()).compareTo(pref2 + o2.getGroupId() + o2.getArtifactId()); + } + }); + + artifacts.forEach((art) -> { + try { + + String detail = keys.get(art.getGroupId() + ":" + art.getArtifactId()); + if (detail == null) { + detail = ""; + } + + ArtifactResult result = resolveArtifact(art); + + HashMap filter = new HashMap<>(); + filter.put("X{detail}", detail); + filter.put("X{group}", art.getGroupId()); + filter.put("X{artifact}", art.getArtifactId()); + filter.put("X{classifier}", result.getArtifact().getClassifier()); + filter.put("X{package}", getPackageName(result.getArtifact())); + filter.put("X{file}", result.getArtifact().getFile().getName()); + filter.put("X{version}", result.getArtifact().getVersion()); + + String uri = getURI(result); + + filter.put("X{uri}", uri); + + if (uri.equals("")) { + filter.put("X{fileMD}", result.getArtifact().getFile().getName()); + } else { + filter.put("X{fileMD}", "[" + result.getArtifact().getFile().getName() + "](" + uri + ")"); + } + + String output = applyFilters(line, filter); + + if (getLog().isDebugEnabled()) { + filter.forEach((a, b) -> { + getLog().debug("filter.put(" + a + ", " + b + ")"); + }); + getLog().debug(output); + } + + + stream.println(output); + + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + }); + if (footer != null) { + stream.println(footer); + } + stream.close(); + } catch (Throwable e) { + getLog().error(e.getMessage(), e); + } + } + + private String getURI(ArtifactResult result) { + Artifact art = result.getArtifact(); + String uri = ""; + if (result.getRepository() instanceof RemoteRepository) { + RemoteRepository remoteRepository = (RemoteRepository) result.getRepository(); + uri = remoteRepository.getUrl(); + } else { + uri = defaultRepo; + } + + return uri + "/" + + art.getGroupId().replace('.', '/') + "/" + + art.getArtifactId() + "/" + + art.getVersion(); + } + +} diff --git a/artemis-website/pom.xml b/artemis-website/pom.xml index bf4a099b92..893199cba1 100644 --- a/artemis-website/pom.xml +++ b/artemis-website/pom.xml @@ -199,6 +199,85 @@ ${skipWebsiteDocGeneration} + + org.apache.activemq + artemis-maven-plugin + ${project.version} + + + doc-jms-client + generate-sources + + dependency-doc + + + ${scratch-dir-user-manual}/client-classpath-jms.md + + org.apache.activemq + jakarta.jms + org.jgroups + io.netty + +
#Artemis JMS Client Dependencies + +File | observation | package +---|---|---
+ X{fileMD}| X{detail} |X{package} + + io.netty:netty-transport-native-epoll + io.netty:netty-transport-classes-epoll + io.netty:netty-transport-native-kqueue + io.netty:netty-transport-classes-kqueue + org.jgroups:jgroups + + + only if you want epoll on Linux + only if you want epoll on Linux + only if you want kqueue on MacOS + only if you want kqueue on MacOS + only if you want JGroups discovery from the clients + + org.apache.activemq:artemis-jms-client:${project.version} +
+
+ + doc-jakarta-client + generate-sources + + dependency-doc + + + ${scratch-dir-user-manual}/client-classpath-jakarta.md + + org.apache.activemq + jakarta.jms + org.jgroups + io.netty + +
#Artemis Jakarta Client Dependencies +File | observation | package +---|---|---
+ X{fileMD}| X{detail} |X{package} + + io.netty:netty-transport-native-epoll + io.netty:netty-transport-classes-epoll + io.netty:netty-transport-native-kqueue + io.netty:netty-transport-classes-kqueue + org.jgroups:jgroups + + + only if you want epoll on Linux + only if you want epoll on Linux + only if you want kqueue on MacOS + only if you want kqueue on MacOS + only if you want JGroups discovery from the clients + + org.apache.activemq:artemis-jakarta-client:${project.version} +
+
+
+
+ maven-antrun-plugin diff --git a/docs/user-manual/en/SUMMARY.md b/docs/user-manual/en/SUMMARY.md index 0d0b1b6a38..ff5d3acfee 100644 --- a/docs/user-manual/en/SUMMARY.md +++ b/docs/user-manual/en/SUMMARY.md @@ -22,6 +22,8 @@ * [Mapping JMS Concepts to the Core API](jms-core-mapping.md) * [Using JMS](using-jms.md) * [The Client Classpath](client-classpath.md) + * [JMS](client-classpath-jms.md) + * [Jakarta](client-classpath-jakarta.md) * [Examples](examples.md) * [Routing Messages With Wild Cards](wildcard-routing.md) * [Wildcard Syntax](wildcard-syntax.md) diff --git a/docs/user-manual/en/client-classpath-jakarta.md b/docs/user-manual/en/client-classpath-jakarta.md new file mode 100644 index 0000000000..db012341fd --- /dev/null +++ b/docs/user-manual/en/client-classpath-jakarta.md @@ -0,0 +1 @@ +This file will be generated/replaced in compile time by artemis-website \ No newline at end of file diff --git a/docs/user-manual/en/client-classpath-jms.md b/docs/user-manual/en/client-classpath-jms.md new file mode 100644 index 0000000000..db012341fd --- /dev/null +++ b/docs/user-manual/en/client-classpath-jms.md @@ -0,0 +1 @@ +This file will be generated/replaced in compile time by artemis-website \ No newline at end of file diff --git a/docs/user-manual/en/client-classpath.md b/docs/user-manual/en/client-classpath.md index b2820fed5e..7a446eb96f 100644 --- a/docs/user-manual/en/client-classpath.md +++ b/docs/user-manual/en/client-classpath.md @@ -10,7 +10,59 @@ Apache ActiveMQ Artemis requires just a single jar on the *client classpath*. > jars from different Apache ActiveMQ Artemis versions. Mixing and matching > different jar versions may cause subtle errors and failures to occur. + +## Maven Packages + +The best way to define a client dependency to your java application is through a maven dependency declaration. + +There are two packages you can choose from, org.apache.activemq:artemis-jms-client or org.apache.activemq:artemis-jakarta-client for both JMS and Jakarta APIs. + +Say you define artemis-version as '{{ config.version }}': + +For JMS: +```xml +... + + org.apache.activemq + artemis-jms-client + ${artemis-version} + +... +``` + +For Jakarta: +```xml +... + + org.apache.activemq + artemis-jakarta-client + ${artemis-version} + +... +``` + +## All clients + +Even though it is highly recommend using maven, in case this is not a possibility the all inclusive jars could be used. + +These jars will be available under ./lib/client on the main distribution: + +- artemis-jakarta-client-all-{{ config.version }}.jar +- artemis-jms-client-all-{{ config.version }}.jar + Whether you are using JMS or just the Core API simply add the `artemis-jms-client-all.jar` from the `lib/client` directory to your client -classpath. This is a "shaded" jar that contains all the Artemis code plus -dependencies (e.g. JMS spec, Netty, etc.). +classpath. + + +**Warning:**These jars will include all the [client's dependencies](client-classpath-jms.md). Be careful with mixing other jars in your application as they may clash with other. + + +## Individual dependencies + +You may also choose to use the jars individually as they are all included under ./lib on the main distribution. + +For more information: + +- [client jms dependencies](client-classpath-jms.md ) +- [client jakarta dependencies](client-classpath-jakarta.md)