How do I conditionally map a directory with Maven RPM plugin? - java

I have written a master parent pom for use with multiple projects.
In this pom we have setup the RPM plugin to package things. I am starting to create a new standard where we want a new top level folder to exist in every repo.
The problem is I need to not fail to create an RPM if the directory does not exist, at least for now.
I have added a mapping like so
<mapping>
<directory>/var/lib/appName/${service}/deploy</directory>
<filemode>775</filemode>
<username>${serviceuser}</username>
<groupname>${servicegroup}</groupname>
<sources>
<source>
<location>deploy</location>
</source>
</sources>
</mapping>
The build fails when the folder does not exist.
The error is
Failed to execute goal org.codehaus.mojo:rpm-maven-plugin:2.1-alpha-4:attached-rpm (default) on project example-service: Source location deploy does not exist -> [Help 1]

Related

How to build uberJar with Quarkus-Gradle-Plugin

I'm trying to build an uberJar with all the dependencies (runnable) using the Quarkus Gradle plugin.
With maven you can build it by adding a config to the plugin.
That's what it looks like in maven:
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.version}</version>
<configuration>
<uberJar>true</uberJar>
</configuration>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
Is there any possibility to set this property in the gradle plugin?
id 'io.quarkus.gradle.plugin' version '0.12.0'
The name of that option is "uber-jar".
To set this property you have to start the build like that from command line:
>gradle quarkusBuild --uber-jar
I had some bugs during the build, like that one
Caused by: java.nio.file.NoSuchFileException: /Users/sven/Idea/getting-started/build/getting-started.jar
but in the end the build was successful
The quarkusBuild task contains a property named uberJar that you can be used to control the uberJar behavior (see this).
You can directly configure the task in your build.gradle using something like:
task buildUberJar(type: io.quarkus.gradle.tasks.QuarkusBuild, dependsOn: build) {
uberJar = true
}
However, I see a lot of issues with overlapping resources between the jars with this approach. Here is a subset of my output:
> Task :service-asset-management:buildUberJar
building quarkus runner
Duplicate entry META-INF/quarkus-extension.json entry from io.quarkus:quarkus-jackson::jar:0.26.1(runtime) will be ignored. Existing file was provided by io.quarkus:quarkus-kubernetes-client::jar:0.26.1(runtime)
Duplicate entry NOTICE entry from org.apache.kafka:kafka-clients::jar:2.2.1(runtime) will be ignored. Existing file was provided by org.ehcache:ehcache::jar:3.6.1(runtime)
Duplicate entry META-INF/quarkus-extension.json entry from io.quarkus:quarkus-arc::jar:0.26.1(runtime) will be ignored. Existing file was provided by io.quarkus:quarkus-kubernetes-client::jar:0.26.1(runtime)
Duplicate entry META-INF/quarkus-extension.json entry from io.quarkus:quarkus-core::jar:0.26.1(runtime) will be ignored. Existing file was provided by io.quarkus:quarkus-kubernetes-client::jar:0.26.1(runtime)
Dependencies with duplicate files detected. The dependencies [org.apache.kafka:kafka-clients::jar:2.2.1(runtime), org.ehcache:ehcache::jar:3.6.1(runtime)] contain duplicate files, e.g. NOTICE
Dependencies with duplicate files detected. The dependencies [io.quarkus:quarkus-core::jar:0.26.1(runtime), io.quarkus:quarkus-jackson::jar:0.26.1(runtime), io.quarkus:quarkus-kubernetes-client::jar:0.26.1(runtime), io.quarkus:quarkus-arc::jar:0.26.1(runtime)] contain duplicate files, e.g. META-INF/quarkus-extension.json
Dependencies with duplicate files detected. The dependencies [commons-logging:commons-logging::jar:1.2(runtime), org.slf4j:jcl-over-slf4j::jar:1.7.25(runtime)] contain duplicate files, e.g. org/apache/commons/logging/impl/SimpleLog$1.class

How to run application found in sub-module from root module?

Given the following Maven project:
root-project
database
server
I am able to configure maven-exec-plugin inside the server sub-module to run the application found therein. However, if someone updates a peer sub-module (e.g. database) then I get runtime errors. What I would like to do instead is have some mechanism that would:
Build root-project and its sub-modules when I build the "current project". I don't mind which project this is, it could be root-project or server.
Runs server when I run the "current project"
This way, I can initiate all project-wide operations from a single point instead of having to context-switch between the two projects.
I tried configuring maven-exec-plugin at root-project to do this, but <classpath/> resolves to root-project's classpath instead of the desired server classpath.
I'm wondering if approaching this from the opposite end is possible (configuring maven-compiler-plugin in server to build root-project and its dependencies) but I'm not sure how to do so. I am also worried that this might set off an endless loop as root-project tries building server and server tries building root-project.
I hope I understood your question correct, it looks like any other project to me:
I've created a project available from https://github.com/johanwitters/stackoverflow-mavenExec
Parent: stackoverflow-mavenExec
Child module 1: database
Child module 2: server
Module "database" has 1 class com.johanw.stackoverflow.database.Database defined as:
package com.johanw.stackoverflow.database;
public class Database {
public static String DATBASE_NAME = "The name";
}
Module "server" depends on module "database".
<dependency>
<groupId>com.johanw.stackoverflow.mavenExec</groupId>
<artifactId>database</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
Module "server" has a exec-maven-plugin plugin defined as:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<id>install</id>
<phase>install</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.johanw.stackoverflow.server.Test</mainClass>
</configuration>
</plugin>
This runs the class com.johanw.stackoverflow.server.Test available from "server", which is defined as:
package com.johanw.stackoverflow.server;
import com.johanw.stackoverflow.database.Database;
public class Test {
public static void main(String[]args) {
System.out.println("Hello " + Database.DATBASE_NAME);
}
}
You mentioned "I don't mind which project this is, it could be root-project or server". So, for the above to work, you'll need to build the root project. When you do, root (parent) project stackoverflow-mavenExec using ...
mvn clean install
... it will eventually run the com.johanw.stackoverflow.server.Test and output
Hello The name
As illustrated below:
If you want to only run the server main class, from within the root directory, run the follwing command.
mvn exec:java -pl server -Dexec.mainClass=com.johanw.stackoverflow.server.Test
If it's your goal to switch between clean install and run server, then you can remove the definition of exec-maven-plugin in the server pom, and run respectively:
mvn clean install
and
mvn exec:java -pl server -Dexec.mainClass=com.johanw.stackoverflow.server.Test
I hope this helps.

How to get name of Maven dependency JAR (not full path) as a pom.xml variable

It looks like it is possible to get the path/to/a/dependency.jar as an expandable variable within a Maven pom.xml: see Can I use the path to a Maven dependency as a property? You can expand, e.g., an expression into a string like /home/pascal/.m2/repository/junit/junit/3.8.1/junit-3.8.1.jar.
What I want instead of the full path to the dependency JAR within my local Maven repository is just the bare name of the JAR, for example junit-3.8.1.jar.
So for example, within my pom.xml, I would like to be able to use a value like ${maven.dependency.junit.junit.jar.name} to expand to junit-3.8.1.jar.
Can I do this, and how?
You can use the maven-antrun-plugin to get the file name of a dependency. Ant has a <basename> task which extracts the file name from a path. As described in Can I use the path to a Maven dependency as a property? the full path name of a dependency is available in ant as ${maven.dependency.groupid.artifactid.type.path}. This enables us to extract the file name with the ant task like this:
<basename file="${maven.dependency.groupid.artifactid.type.path}" property="dependencyFileName" />
This stores the file name in a property named dependencyFileName.
In order to make this property availbable in the pom, the exportAntProperties configuration option of the maven-antrun-plugin needs to be enabled. This option is only available as of version 1.8 of the plugin.
This example shows the plugin configuration for retrieving the artifact file name of the junit dependency:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>initialize</phase>
<configuration>
<exportAntProperties>true</exportAntProperties>
<tasks>
<basename file="${maven.dependency.junit.junit.jar.path}"
property="junitArtifactFile"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
No, I'm sorry to say that it isn't possible. So, you have two options before you.
1) modify the maven source code and contribute the modification.
2) write your own plug-in.
I recommend the second option. Writing plug-ins is not that hard. As a philosophical principal, select a frequently-used plug-in which has functionality close to what you want to accomplish. Read and understand the code, and then modify it to do what you desire.
So for your example, you might look at the filter plugin. There's also some interesting syntax going on in the Ant plugin. It allows you to name dependencies and get those jar filenames into the embedded Ant script.
Good luck. :-)
As a more practical alternative, you might just break down and manually code the property value with the exact version number you're using. You're not going to switch the version number that often, right? And this is only one jar you're dealing with, right?

Deploy with maven plugin on remote weblogic 12c

I have weblogic 12c on machine 192.168.1.3. I want to deploy ear from machine 192.168.1.2 with maven plugin:
<groupId>com.oracle.weblogic</groupId>
<artifactId>wls-maven-plugin</artifactId>
<version>12.1.1.0</version>
In the first phase I made in the project:
mvn wls:install
Plugin configuration looks like this:
<configuration>
<adminurl>t3://192.168.1.3:7001</adminurl>
<user>weblogic</user>
<password>welcome1</password>
<debug>true</debug>
<name>test-ear-dev01</name>
<remote>true</remote>
<upload>true</upload>
<advanced>true</advanced>
<failOnError>true</failOnError>
<artifactLocation>c:\Users\bartek\Downloads\wls1211_dev.zip</artifactLocation>
</configuration>
next I make
mvn wls:deploy
and I get following error
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Invalid file. Please provide an existing fully qualified path of the file.
[DEBUG] Trace
org.apache.maven.lifecycle.LifecycleExecutionException: Invalid file. Please provide an existing fully qualified path of the file.
at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:719)
...
...
...
Caused by: org.apache.maven.plugin.MojoExecutionException: Invalid file. Please provide an existing fully qualified path of the file.
at weblogic.tools.maven.plugins.deploy.DeployerMojo.handleDeployerException(DeployerMojo.java:459)
...
Caused by: org.apache.maven.plugin.MojoExecutionException: Invalid file. Please provide an existing fully qualified path of the file.
at weblogic.tools.maven.plugins.deploy.DeployerMojo.getSourceParameter(DeployerMojo.java:434)
...
Can you tell me what I'm doing wrong, when deploy ear to a remote server
The configuration you show looks like what you used to install WebLogic with the install goal of the plugin. <artifactLocation> is a configuration element for that goal, not deploy, per the documentation.
For the deploy goal, replace <artifactLocation> with <source>, which contains the name of your ear file.

Maven AppAssembler not finding class

Attempting to modify an existing Java/Tomcat app for deployment on Heroku following their tutorial and running into some issues with AppAssembler not finding the entry class. Running target/bin/webapp (or deploying to Heroku) results in Error: Could not find or load main class org.stopbadware.dsp.Main
Executing java -cp target/classes:target/dependency/* org.stopbadware.dsp.Main runs properly however. Here's the relevant portion of pom.xml:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.1.1</version>
<configuration>
<assembleDirectory>target</assembleDirectory>
<programs>
<program>
<mainClass>org.stopbadware.dsp.Main</mainClass>
<name>webapp</name>
</program>
</programs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
My guess is mvn package is causing AppAssembler to not use the correct classpath, any suggestions?
Your artifact's packaging must be set to jar, otherwise the main class is not found.
<pom>
...
<packaging>jar</packaging>
...
</pom>
The artifact itself is added at the end of the classpath, so nothing other than a JAR file will have any effect.
Try:
mvn clean package jar:jar appassembler:assemble
Was able to solve this by adding "$BASEDIR"/classes to the CLASSPATH line in the generated script. Since the script gets rewritten on each call of mvn package I wrote a short script that calls mvn package and then adds the needed classpath entry.
Obviously a bit of a hack but after a 8+ hours of attempting a more "proper" solution this will have to do for now. Will certainly entertain any more elegant ways of correcting the classpath suggested here.
I was going through that tutorial some time ago and had very similar issue. I came with a bit different approach which works for me very nicely.
First of all, as it was mentioned before, you need to keep your POM's type as jar (<packaging>jar</packaging>) - thanks to that, appassembler plugin will generate a JAR file from your classes and add it to the classpath. So thanks to that your error will go away.
Please note that this tutorial Tomcat is instantiated from application source directory. In many cases that is enough, but please note that using that approach, you will not be able to utilize Servlet #WebServlet annotations as /WEB-INF/classes in sources is empty and Tomcat will not be able to scan your servlet classes. So HelloServlet servlet from that tutorial will not work, unless you add some additional Tomcat initialization (resource configuration) as described here (BTW, you will find more SO questions talking about that resource configuration).
I did a bit different approach:
I run a org.apache.maven.plugins:maven-war-plugin plugin (exploded goal) during package and use that generated directory as my source directory of application. With that approach my web application directory will have /WEB-INF/classes "populated" with classes. That in turn will allow Tomcat to perform scanning job correctly (i.e. Servlet #WebServlet annotations will work).
I also had to change a source of my application in the launcher class:
public static void main(String[] args) throws Exception {
// Web application is generated in directory name as specified in build/finalName
// in maven pom.xml
String webappDirLocation = "target/embeddedTomcatSample/";
Tomcat tomcat = new Tomcat();
// ... remaining code does not change
Changes to POM which I added - included maven-war-plugin just before appassembler plugin:
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
</plugin>
...
Please note that exploded goal is called.
I hope that small change will help you.
One more comment on that tutorial and maven build: note that the tutorial was written to show how simple is to build an application and run it in Heroku. However, that is not the best approach to maven build.
Maven recommendation is that you should adhere to producing one artifact per POM. In your case there are should two artifacts:
Tomcat launcher
Tomcat web application
Both should be build as separate POMs and referenced as modules from your parent POM. If you look at the complexity of that tutorial, it does not make much sense to split that into two modules. But if your applications gets more and more complex (and the launcher gets some additional configurations etc.) it will makes a lot of sense to make that "split". As a matter of fact, there are some "Tomcat launcher" libraries already created so alternatively you could use of one them.
You can set the CLASSPATH_PREFIX environment variable:
export CLASSPATH_PREFIX=target/classes
which will get prepended to the classpath of the generated script.
The first thing is that you are using an old version of appassembler-maven-plugin the current version is 1.3.
What i don't understand why are you defining the
<assembleDirectory>target</assembleDirectory>
folder. There exists a good default value for that. So usually you don't need it. Apart from that you don't need to define an explicit execution which bounds to the package phase, cause the appassembler-maven-plugin is by default bound to the package phase.
Furthermore you can use the useWildcardClassPath configuration option to make your classpath shorter.
<configuration>
<useWildcardClassPath>true</useWildcardClassPath>
<repositoryLayout>flat</repositoryLayout>
...
</configruation>
And that the calling of the generated script shows the error is depending on the thing that the location of the repository where all the dependencies are located in the folder is different than in the generated script defined.

Categories