I want to rename static files when building my WAR file using maven-war-plugin, with version number. For intance, in my project I have a file:
src/main/webapp/css/my.css
I want it to appear in the WAR file as:
css/my-versionNumber.css
The same question was already asked (see Rename static files on maven war build), but the accepted answer is to rename a directory. I do not want to rename a directory, I want to rename the actual file.
Is this possible?
OK, I found a way, the principles come from: Automatic update of generated css files via m2e.
Renaming files
I chose to use Maven AntRun Plugin, because it allows to rename several files using a replacement pattern, see https://stackoverflow.com/a/16092997/1768736 for details.
Alternative solutions were to use:
maven-assembly-plugin: but it doesn't support renaming of filesets, only renaming of individual files (see file assembly descriptor and comments of this answer: https://stackoverflow.com/a/4019057/1768736)
maven-resources-plugin: it allows to copy resources, not to rename them (see copy resources mojo and comments of this question: Renaming resources in Maven)
Make renamed files available for maven-war-plugin
Copy files: the idea is to copy the renamed files into a temp directory, to be added by maven-war-plugin to the WAR file as a web-resource. maven-war-plugin builds the WAR during the packaging phase, so we will need to copy renamed files before that.
Prevent maven-war-plugin to manage the files to be renamed by maven-antrun-plugin: this is done by using the parameter warSourceExcludes.
Make it work from within Eclipse with m2e-wtp
Change lifecycle mapping: the problem is that m2e by default doesn't execute all lifecycles defined in the POM file (to see the lifecycles executed/ignored, from Eclipse, go to your project properties, then Maven > Lifecycle Mapping). So you need to use the fake plugin org.eclipse.m2e.lifecycle-mapping to add the maven-antrun-plugin lifecycle, see life cycle mapping documentation.
Change maven-antrun-plugin output directory: the problem is that m2e-wtp acquires its web-resources before any lifecycle can be launched, so, before maven-antrun-plugin can rename the files. As a workaround, we create a profile, activated only when the project is built by m2e, to change the property used to set maven-antrun-plugin output directory, to write directly into m2e-wtp web-resources.
That's it! POM snippet:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<properties>
<!-- properties used to rename css files with version number. -->
<css.version>${project.version}</css.version>
<!-- Temp directory where to copy renamed files, later added by maven-war-plugin as web-resources. -->
<rename.tmp.directory>${project.build.directory}/rename_tmp</rename.tmp.directory>
</properties>
<!-- There is a problem when running the webapp from Eclipse: m2e-wtp acquires
the web-resources before any lifecycle can be launched, so, before
maven-antrun-plugin can rename the files. We define a profile so that
maven-antrun-plugin copies files directly into the m2e-wtp web-resources directory,
when running from Eclipse. -->
<profiles>
<profile>
<id>m2e</id>
<!-- This profile is only active when the property "m2e.version"
is set, which is the case when building in Eclipse with m2e,
see https://stackoverflow.com/a/21574285/1768736. -->
<activation>
<property>
<name>m2e.version</name>
</property>
</activation>
<properties>
<rename.tmp.directory>${project.build.directory}/m2e-wtp/web-resources/</rename.tmp.directory>
</properties>
</profile>
</profiles>
...
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>run</goal>
</goals>
<id>rename-resources</id>
<!-- perform copy before the package phase,
when maven-war-plugin builds the WAR file -->
<phase>process-resources</phase>
<configuration>
<target>
<!-- copy renamed files. -->
<copy todir="${rename.tmp.directory}/css/">
<fileset dir="src/main/webapp/css/">
<include name="**/*.css" />
</fileset>
<!-- See other Mappers available at http://ant.apache.org/manual/Types/mapper.html -->
<mapper type="glob" from="*.css" to="*-${css.version}.css"/>
</copy>
</target>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<!-- We do no let the maven-war-plugin take care of files that will be renamed.
Paths defined relative to warSourceDirectory (default is ${basedir}/src/main/webapp) -->
<warSourceExcludes>css/</warSourceExcludes>
<webResources>
<!-- include the resources renamed by maven-antrun-plugin,
at the root of the WAR file -->
<resource>
<directory>${rename.tmp.directory}</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
...
</plugins>
<!-- When running server from Eclipse, we need to tell m2e to execute
maven-antrun-plugin to rename files, by default it doesn't. We need to modify the life cycle mapping. -->
<pluginManagement>
<plugins>
<!-- This plugin is not a real one, it is only used by m2e to obtain
config information. This is why it needs to be put in the section
pluginManagement, otherwise Maven would try to download it. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<versionRange>[1.0.0,)</versionRange>
<goals>
<goal>run</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute>
<!-- set to true, otherwise changes are not seen,
e.g., to a css file, and you would need to perform
a project update each time. -->
<runOnIncremental>true</runOnIncremental>
</execute >
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
...
</build>
...
</project>
You need define
<properties>
<css.version>1.1.0</css.version>
</properties>
After that call it by EL
css/${css.version}.css
Related
I'd like to synchronize log4j and logback config files across multiple projects. I have one project (Project A) that contains the log4j and logback dependencies, along with the config files.
Project A
src/test/resources
log4j2.xml
logback-test.xml
Project B has a dependency on Project A. I would like to include the log config files in Project A's JAR and have them automatically put in a specific target folder in Project B when resolving Maven dependencies for Project B.
I have tried maven-jar-plugin in Project A but it doesn't seem to work for my purpose.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<includes>
<include>src/test/resources/log4j2.xml</include>
<include>src/test/resources/logback-test.xml</include>
</includes>
</configuration>
</plugin>
Any help would be appreciated.
Thanks!
UPDATE:
While Eugene's answer was accepted, I needed to add a <resources> entry so the log config files would be included in the packaged JAR.
<build>
<resources>
<resource>
<directory>src/test/resources</directory>
<includes>
<include>log4j2.xml</include>
<include>logback-test.xml</include>
</includes>
</resource>
</resources>
</build>
Executing mvn clean compile assembly:single deploy from Project A created and deployed the JAR with the log files included.
[INFO] --- maven-remote-resources-plugin:1.7.0:bundle (default) # project-a ---
[INFO] Writing META-INF/maven/remote-resources.xml descriptor with 2 entries
Executing mvn clean compile from Project B copied the files into the output directory
[INFO] --- maven-remote-resources-plugin:1.7.0:process (default) # project-b ---
[INFO] Preparing remote bundle com.my.projects:project-a:1.0-SNAPSHOT
[INFO] Copying 2 resources from 1 bundle.
You can use Apache Maven Remote Resources Plugin
This plugin is used to retrieve JARs of resources from remote
repositories, process those resources, and incorporate them into JARs
you build with Maven.
A very common use-case is the need to package certain resources in a
consistent way across your organization. For example at Apache, it is
required that every JAR produced contains a copy of the Apache license
and a notice file that references all used software in a given project
Define in Project A which resources you want to share or better create separate project for shared resources
<build>
<plugins>
<plugin>
<artifactId>maven-remote-resources-plugin</artifactId>
<version>1.7.0</version>
<executions>
<execution>
<goals>
<goal>bundle</goal>
</goals>
</execution>
</executions>
<configuration>
<resourcesDirectory>src/test/resources/</resourcesDirectory>
<includes>
<include>log4j2.xml</include>
<include>logback-test.xml</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
Maven will create resources bundle file for sharing resources
${basedir}/target/classes/META-INF/maven/remote-resources.xml
<remoteResourcesBundle xsi:schemaLocation="http://maven.apache.org/remote-resources/1.1.0 https://maven.apache.org/xsd/remote-resources-1.1.0.xsd"
xmlns="http://maven.apache.org/remote-resources/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<remoteResources>
<remoteResource>log4j2.xml</remoteResource>
<remoteResource>logback-test.xml</remoteResource>
</remoteResources>
<sourceEncoding>UTF-8</sourceEncoding>
</remoteResourcesBundle>
See documentation
Configure other modules to use the shared resources
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
<version>1.7.0</version>
<configuration>
<outputDirectory>[your output directory]</outputDirectory>
<resourceBundles>
<!--The resource bundles that will be retrieved and processed. For example: org.test:shared-resources:${project.version}-->
<resourceBundle>groupId:artifactId:version[:type[:classifier]]</resourceBundle>
</resourceBundles>
</configuration>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
See documentation
Alternative solution:
Apache Maven Dependency Plugin It can copy and/or unpack artifacts from local or remote repositories to a specified location.
It was described there Maven: Extract dependency resources before test
and there Use a dependency's resources?
UPDATE:
Example how to add resources:
<project>
...
<build>
...
<resources>
<resource>
<directory>[your folder 1 here]</directory>
</resource>
<resource>
<directory>[your folder 2 here]</directory>
</resource>
</resources>
...
</build>
...
</project>
See documentation
Please don't put logging configuration files into JARs, if someone depends on your JAR, your configuration may overwrite theirs. That depends on which JAR is loaded first
If you want, like this. And package them into JAR
src/main/resources
log4j2.xml
logback.xml
Question: is there any way in Maven (without resorting to an ant plugin) to unzip a file, cd into the directory, remove the file, and the rezip it, all as part of the build?
This is necessary as it is a complex build and also do not want to have to use gradle to accomplish this task.
The requirement of unzipping, removing file and zipping again can also be met in one single step by the truezip-maven-plugin and its remove goal which:
Remove a set of files from an existing archive.
The official examples also cover this scenario.
Given the following snippet:
<properties>
<archive>${project.basedir}/sample.zip</archive>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>truezip-maven-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<id>remove-a-file</id>
<goals>
<goal>remove</goal>
</goals>
<phase>package</phase>
<configuration>
<fileset>
<!-- note how the archive is treated as a normal file directory -->
<directory>${archive}</directory>
<includes>
<include>hello.txt</include>
</includes>
</fileset>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
And executing:
mvn clean package
The build will process the ${archive} file (in this case a sample.zip at the same level of the pom.xml file, that is, in the project.basedir directory) and remove from it the hello.txt file. Then rezip everything.
I just tested it successfully, you can even skip the properties section if not required. However, you should also carefully know that:
The zip file should not be under version control, otherwise it would create conflicts at each build
The behavior most probably should not be part of the default Maven build, hence good candidate for a Maven profile
the plugin replaces the original file, so if that was an issue you could firstly copy it to another location and then process it as above. To copy it, you could use the maven-resources-plugin and its copy-resources goal.
When I am importing my maven project in my eclipse, I am getting this error:
Plugin execution not covered by lifecycle configuration:
org.codehaus.mojo:buildnumber-maven-plugin:1.0:create-timestamp
(execution: generate-build-number, phase:
generate-sources) pom.xml /DataClient line 6 Maven Project
Does anyone know how to fix this problem? I tried several other ways which was listed in SO questions but it didn't worked.
I am using eclipse kepler and I do have pluginManagement as well in my pom.xml file.
My pom.xml snippet where I am using plugins:
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-javaagent:"${settings.localRepository}"/com/googlecode/jmockit/jmockit/1.7/jmockit-1.7.jar</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<configuration>
<instrumentation>
<excludes>
<exclude>**/test/**/*.class</exclude>
</excludes>
</instrumentation>
<formats>
<format>xml</format>
<format>html</format>
</formats>
</configuration>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<author>false</author>
<keywords>true</keywords>
<show>public</show>
<links>
<link>http://docs.guava-libraries.googlecode.com/git-history/v16.0/javadoc/</link>
<link>http://netty.io/4.0/api/</link>
</links>
<doctitle>Data Client API (${project.version})</doctitle>
<windowtitle>Data Client API (${project.version})</windowtitle>
<groups>
<group>
<title>Core API</title>
<packages>com.host.grads.client:com.host.grads.client.resources</packages>
</group>
<group>
<title>Miscellaneous</title>
<packages>com.host.grads.client.utils</packages>
</group>
</groups>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
I found this on SO and I think that it is the answer to your problem : Plugin execution not covered by lifecycle configuration (JBossas 7 EAR archetype)
I copy the text initially written by Jan :
This is a "feature" of the M2E plugin that had been introduced a while ago. It's not directly related to the JBoss EAR plugin but also happens with most other Maven plugins.
If you have a plugin execution defined in your pom (like the execution of maven-ear-plugin:generate-application-xml), you also need to add additional config information for M2E that tells M2E what to do when the build is run in Eclipse, e.g. should the plugin execution be ignored or executed by M2E, should it be also done for incremental builds, ... If that information is missing, M2E complains about it by showing the "Plugin execution not covered by lifecycle configuration" error message.
See here for a more detailed explanation and some sample config that needs to be added to the pom to make that error go away:
https://www.eclipse.org/m2e/documentation/m2e-execution-not-covered.html
If you need to implement this solution, you can have a look to this comment of the previously mentioned question : https://stackoverflow.com/a/26447353/4810148
Here is a copy of what coderplus answered. Of course you will have to replace the groupId and artifactId by the ones of the plugin that is concerned by your case.
Eclipse has got the concept of incremental builds.This is incredibly useful as it saves a lot of time.
How is this Useful
Say you just changed a single .java file. The incremental builders will be able to compile the code without having to recompile everything(which will take more time).
Now what's the problem with Maven Plugins
Most of the maven plugins aren't designed for incremental builds and hence it creates trouble for m2e. m2e doesn't know if the plugin goal is something which is crucial or if it is irrelevant. If it just executes every plugin when a single file changes, it's gonna take lots of time.
This is the reason why m2e relies on metadata information to figure out how the execution should be handled. m2e has come up with different options to provide this metadata information and the order of preference is as below(highest to lowest)
pom.xml file of the project
parent, grand-parent and so on pom.xml files
[m2e 1.2+] workspace preferences
installed m2e extensions
[m2e 1.1+] lifecycle mapping metadata provided by maven plugin
default lifecycle mapping metadata shipped with m2e
1,2 refers to specifying pluginManagement section in the tag of your pom file or any of it's parents. M2E reads this configuration to configure the project.Below snippet instructs m2e to ignore the jslint and compress goals of the yuicompressor-maven-plugin
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings
only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>net.alchim31.maven</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<versionRange>[1.0,)</versionRange>
<goals>
<goal>compress</goal>
<goal>jslint</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore />
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
3) In case you don't prefer polluting your pom file with this metadata, you can store this in an external XML file(option 3). Below is a sample mapping file which instructs m2e to ignore the jslint and compress goals of the yuicompressor-maven-plugin
<?xml version="1.0" encoding="UTF-8"?>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>net.alchim31.maven</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<versionRange>[1.0,)</versionRange>
<goals>
<goal>compress</goal>
<goal>jslint</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore/>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
4) In case you don't like any of these 3 options, you can use an m2e connector(extension) for the maven plugin.The connector will in turn provide the metadata to m2e. You can see an example of the metadata information within a connector at this link . You might have noticed that the metadata refers to a configurator. This simply means that m2e will delegate the responsibility to that particular java class supplied by the extension author.The configurator can configure the project(like say add additional source folders etc) and decide whether to execute the actual maven plugin during an incremental build(if not properly managed within the configurator, it can lead to endless project builds)
Refer these links for an example of the configuratior(link1,link2). So in case the plugin is something which can be managed via an external connector then you can install it. m2e maintains a list of such connectors contributed by other developers.This is known as the discovery catalog. m2e will prompt you to install a connector if you don't already have any lifecycle mapping metadata for the execution through any of the options(1-6) and the discovery catalog has got some extension which can manage the execution.
The below image shows how m2e prompts you to install the connector for the build-helper-maven-plugin.
.
5)m2e encourages the plugin authors to support incremental build and supply lifecycle mapping within the maven-plugin itself.This would mean that users won't have to use any additional lifecycle mappings or connectors.Some plugin authors have already implemented this
6) By default m2e holds the lifecycle mapping metadata for most of the commonly used plugins like the maven-compiler-plugin and many others.
Now back to the question :You can probably just provide an ignore life cycle mapping in 1, 2 or 3 for that specific goal which is creating trouble for you.
The "install" goal copies the artifact to the target directory and to the local repository.
How can I tell Maven to copy it also to a given directory (like the deploy directory of JBoss for example).
The goal copy of maven-dependency-plugin does what you want, see the example.
It is however not a good idea to copy anything outside your target directory (or ${project.build.directory} to be precise) - especially if such action is attached to a build phase, because it introduces unexpected side-effects of the build, and sometimes even loss of reproducibility.
As #Andreas_D notes, there is a better alternative for JBoss deployment purpose; similarly for deploying to other appservers.
According to http://maven.apache.org/plugins/maven-dependency-plugin/examples/copying-artifacts.html you can copy the just built artifact to a specific directory:
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<id>copy-installed</id>
<phase>install</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<type>${project.packaging}</type>
</artifactItem>
</artifactItems>
<outputDirectory>some-other-place</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
</project>
If you want to copy file to a webserver (local or distant) you can use Maven upload plugin :
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-upload-plugin</artifactId>
<version>1.1</version>
<configuration>
<resourceSrc>
${project.build.directory}/${project.build.finalName}.${project.packaging}
</resourceSrc>
<resourceDest>${jboss.deployDir}</resourceDest>
<serverId>${jboss.host}</serverId>
<url>${jboss.deployUrl}</url>
</configuration>
</plugin>
And to configure parameters in a smart way, I use maven profiles :
<profiles>
<!-- local deployment -->
<profile>
<id>developpement</id>
<properties>
<jboss.host>localhost</jboss.host>
<jboss.deployDir>appli/jboss-4.0.4.GA/server/default/deploy/</jboss.deployDir>
<jboss.deployUrl>file://C:/</jboss.deployUrl>
</properties>
</profile>
<!-- distant deployment -->
<profile>
<id>validation</id>
<properties>
<jboss.host>ENV_val</jboss.host>
<jboss.deployDir>/home/envval/jboss/server/default/deploy/</jboss.deployDir>
<jboss.deployUrl>scp://PROJECT_LAN_HOST</jboss.deployUrl>
</properties>
</profile>
</profiles>
I've created an "ant launcher", to use it by clicking under Eclipse ant view :
<target name="copy war to JBoss local" description="Copy war to local JBoss">
<maven goal="upload:upload" options="-Pdeveloppement" />
</target>
But you can simply run it on a command line :
mvn upload:upload -Pdeveloppement
By the way, for distant deployment, you may need a login password for scp to work. You have to add them to you Maven settings.xml file :
<settings>
...
<servers>
<server>
<id>ENV_val</id>
<username>login</username>
<password>password</password>
</server>
</servers>
...
</settings>
The best approach would be to use a plugin which will actually deploy your application, such as cargo or jboss-maven plugin (credit to #Andreas_D for that one).
This would be a better approach to using a copy or generic upload tool since deploying is what you are actually trying to do.
With the cargo plugin you have the option to deploy to a variety of running servers. We took this approach to test locally in jetty using the jetty plugin during the build and had a profile to deploy to tomcat on demand via cargo.
Note: If you have your target server (JBOSS) installed locally on the dev box as well then you can also use cargo to start/stop your server during your build process as well. The downside of this approach is that you will need it to reference it's location in the pom file, so either all devs install it in the same location or a system property that defines where it is located (similar to JAVA_HOME).
We have a Maven build (version 2.2.1) that currently produces a WAR file. Our output directory is target/, so we end up with a build artifact target/MyWar.WAR.
I'm adding two profiles to our POM.xml file to facilitate specific build "flavors" that each require a specific version of an A.xml file. In the intermediate build directory target/MyWar/ there are 3 files:
A.xml
A_1.xml
A_2.xml
Building in Maven without a specified profile should use A.xml, and it does currently. I want to use maven-antrun-plugin to (for Profile 1) replace A.xml with A_1.xml, and for Profile 2 replace A.xml with A_2.xml. (Removing the _1 and _2 suffixes.)
This is an example of Profile 1's execution:
<profile>
<id>Profile1</id>
<build>
...
<execution>
<id>Profile1-Replace</id>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<delete
file="${project.build.outputDirectory}/../MyWar/A.xml" />
<copy
file="${project.build.outputDirectory}/../MyWar/A_1.xml"
tofile="${project.build.outputDirectory}/../MyWar/A.xml" />
</tasks>
</configuration>
</execution>
...
</build>
</profile>
This correctly replaces the files in the intermediate target/MyWar/ directory, but for whatever reason the final WAR that's being produced in target does not reflect these changes.
It's as if running in the 'package' phase is too late, and the WAR has already been built. Changing the phase to 'compile' or 'test', the immediately-previous phases, complain because the A.xml file (and the intermediate build directory) have not even been created yet.
I would suggest to use the process-resources phase instead, or even generate-resources, if you feel that is a better fit. As a last resort, use prepare-package. But the package phase is the wrong place to do this sort of thing. All such modifications might typically occur directly in the source tree.
However, if you do the file manipulation in a separate directory, then you can add it during the package phase using the maven-war-plugin as follows:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webResources>
<resource>
<directory>A_variant</directory>
</resource>
</webResources>
</configuration>
</plugin>
Of course if you need to go this route, it would be simpler to keep three directories and choose the appropriate one in your profile.