How can I use maven profile Id value in spring bean files? - spring

mvn -P dev
If I build my project using profile dev, then I want to use dev.properties in my spring bean like below. Is it possible ? If so , how could I get profile name ?
<bean id="xyz" class="abc.xyz">
<property name="propertyFile" value="${maven_profile_id}.properties" />
</bean>
Thanks in advance.

You can use Maven profiles to add a 'profile' property to the build:
<profiles>
<profile>
<id>dev</id>
<properties>
<profile>dev</profile>
</properties>
</profile>
</profiles>
Then pass the value into your application using a system property, here's an example with surefire:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<profile>${profile}</profile>
</systemPropertyVariables>
</configuration>
</plugin>
Finally this can be referenced in you application:
<bean id="xyz" class="abc.xyz">
<property name="propertyFile" value="${profile}.properties" />
</bean>
Alternatively, if you are using Spring 3.1 or later you might find the XML profile feature meets your needs (although it may be overkill).

Create a properties file that will be populated using Maven's resource filtering that specifies the profile you are using at build time.
build.properties
activatedProfile=${profileId}
pom.xml (You don't need to filter the complete directory, customise as required)
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resources>
</build>
Add a profileId (or whatever you want to call it) property under each different profile:
<profile>
<id>dev</id>
<properties>
<profileId>dev</profileId>
</properties>
</profile>
<profile>
<id>qa</id>
<properties>
<profileId>qa</profileId>
</properties>
</profile>
You can then use ${activatedProfile}.properties as value for a bean
<bean id="xyz" class="abc.xyz">
<property name="propertyFile" value="${activatedProfile}.properties" />
</bean>

Related

LocalRepositoryNotAccessibleException Could not create local repository at /testartifacts/m2repository

I'm running a CI pipeline in Azure DevOps with a Maven build step called "Download provided dependency JARs".
This step was working before, however it's suddenly giving me this error:
org.apache.maven.repository.LocalRepositoryNotAccessibleException: Could not create local repository at /testartifacts/m2repository
I'm also getting a warning:
##[warning]Could not parse the effective POM.
This is what it looks like in DevOps:
I've set it to clean the working directory before the build is run, but this didn't help.
From what I've read, it seems to be a permissions issue.
Shouldn't the build agent already have permissions?
I appreciate your help.
This is my pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>au.com.mycompany.perfunittests</groupId>
<artifactId>myapplication</artifactId>
<version>1.0-SNAPSHOT</version>
<profiles>
<!-- Load Test -->
<profile>
<id>profile.loadTest</id>
<!-- Test will only be chosen when -DtestType=load -->
<activation>
<!-- Test will be chosen when property testname is not supplied, i.e. the default -->
<property>
<name>!testname</name>
</property>
</activation>
<properties>
<testname>loadtest.myapplication</testname>
<isbenchmarktest>false</isbenchmarktest>
</properties>
</profile>
<!-- Benchmark Test for Common -->
<profile>
<id>profile.benchmarkTest.Common</id>
<activation>
<property>
<name>testname</name>
<value>unittest.myapplication.common</value>
</property>
</activation>
<properties>
<testname>unittest.myapplication.common</testname>
<isbenchmarktest>true</isbenchmarktest>
</properties>
</profile>
<!-- Benchmark Test for Configuration -->
<profile>
<id>profile.benchmarkTest.Configuration</id>
<activation>
<property>
<name>testname</name>
<value>unittest.myapplication.configuration</value>
</property>
</activation>
<properties>
<testname>unittest.myapplication.configuration</testname>
<isbenchmarktest>true</isbenchmarktest>
</properties>
</profile>
<!-- Benchmark Test for Dashboard - note this is legacy Dashboard API calls -->
<profile>
<id>profile.benchmarkTest.Dashboard</id>
<activation>
<property>
<name>testname</name>
<value>unittest.myapplication.dashboard</value>
</property>
</activation>
<properties>
<testname>unittest.myapplication.dashboard</testname>
<isbenchmarktest>true</isbenchmarktest>
</properties>
</profile>
<!-- Benchmark Test for Management -->
<profile>
<id>profile.benchmarkTest.Management</id>
<activation>
<property>
<name>testname</name>
<value>unittest.myapplication.management</value>
</property>
</activation>
<properties>
<testname>unittest.myapplication.management</testname>
<isbenchmarktest>true</isbenchmarktest>
</properties>
</profile>
</profiles>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- No need to run deploy lifecycle -->
<maven.deploy.skip>true</maven.deploy.skip>
<!-- No need to create a JAR -->
<jar.skipIfEmpty>true</jar.skipIfEmpty>
<maven.install.skip>true</maven.install.skip>
<!-- Run in perftest env unless overridden using -Denv -->
<env>perf</env>
</properties>
<repositories>
<repository>
<id>mycompanyproject-visualstudio.com-maven</id>
<url>https://mycompanyproject.pkgs.visualstudio.com/_packaging/maven/maven/v1</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>com.lazerycode.jmeter</groupId>
<artifactId>jmeter-maven-plugin</artifactId>
<version>2.8.6</version>
<executions>
<execution>
<id>jmeter-tests</id>
<goals>
<goal>jmeter</goal>
</goals>
</execution>
</executions>
<configuration>
<jmeterVersion>5.0</jmeterVersion>
<!-- JMX file for unittests lives in the same directory as pom.xml -->
<testFilesDirectory>${project.basedir}</testFilesDirectory>
<testFilesIncluded>
<jMeterTestFile>${testname}.jmx</jMeterTestFile>
</testFilesIncluded>
<!-- Need to save in CSV format for lightning plugin -->
<resultsFileFormat>csv</resultsFileFormat>
<!-- Don't append timestamp to JTL file, so lightning can find it more easily -->
<testResultsTimestamp>false</testResultsTimestamp>
<!-- Don't stop the test on a failure -->
<ignoreResultFailures>true</ignoreResultFailures>
<propertiesUser>
<env>${env}</env>
<url.myapplication>perfweb.myapplication.com</url.myapplication>
<unittest.path.resources>${project.basedir}</unittest.path.resources>
<unittest.path.testdata>${project.basedir}/data</unittest.path.testdata>
</propertiesUser>
<!-- Additional output JTL format for lightning plugin -->
<propertiesJMeter>
<httpclient.reset_state_on_thread_group_iteration>false</httpclient.reset_state_on_thread_group_iteration>
<jmeter.save.saveservice.print_field_names>true</jmeter.save.saveservice.print_field_names>
<jmeter.save.saveservice.successful>true</jmeter.save.saveservice.successful>
<jmeter.save.saveservice.label>true</jmeter.save.saveservice.label>
<jmeter.save.saveservice.time>true</jmeter.save.saveservice.time>
</propertiesJMeter>
<customPropertiesFiles>
<file>${project.basedir}/${testname}.threadgroups.conf</file>
</customPropertiesFiles>
<!-- Additional libraries (mostly) from jmeter-plugins.org -->
<jmeterExtensions>
<artifact>au.com.mycompany:timinglistener:0.2-SNAPSHOT</artifact>
<artifact>com.google.code.gson:gson:2.8.2</artifact>
<artifact>com.opencsv:opencsv:4.1</artifact>
<artifact>com.sumologic.plugins.log4j:sumologic-log4j2-appender:1.7</artifact>
</jmeterExtensions>
<jMeterProcessJVMSettings>
<xms>2048</xms>
<xmx>2048</xmx>
<arguments>
<argument>-Dunittest.path.logs=${project.build.directory}/jmeter/logs</argument>
<argument>-Dunittest.testname=${testname}</argument>
<argument>-Dlog4j.configurationFile=file://${project.basedir}/log4j2.xml</argument>
</arguments>
</jMeterProcessJVMSettings>
<downloadExtensionDependencies>true</downloadExtensionDependencies>
</configuration>
</plugin>
<plugin>
<groupId>uk.co.automatictester</groupId>
<artifactId>jmeter-lightning-maven-plugin</artifactId>
<version>1.5.0</version>
<executions>
<execution>
<goals>
<goal>lightning</goal>
</goals>
<configuration>
<mode>verify</mode>
<!-- Lightning XML definition file lives in the same directory as pom.xml -->
<testSetXml>${project.basedir}/${testname}.xml</testSetXml>
<!-- Test output JTL file written to target/jmeter/results/<testname>.csv -->
<jmeterCsv>${project.build.directory}/jmeter/results/${testname}.csv</jmeterCsv>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
It looks you ran your pipeline on self-hosted agent. Or you configured the maven to retrieve the dependencies from the local repository(in mvnsettings.xml, or .m2/settings.xml ). If you ran your pipeline on self-hosted agent. You can check if the local repo /testartifacts/m2repository exists.
If you run your pipeline on cloud agents, you need to find which setting files configured the the local repo, And remove the localRepository.
Then you might need to use Maven Authenticate task to provides credentials for Azure Artifacts feeds and external Maven repositories.
Add Maven Authenticate task at the top of your pipeline. And select your azure maven feed from the Feeds dropdown list
This task will store the credentials on a temp settings.xml file(with feed name as the server id, see below) on the agent, which will be used to authenticate the maven repository in the following maven task.
Noted: The repository id you specified in your pom.xml file(ie. see below highlighted) should be the same with the name of your azure artifacts maven feed. Or it will still fail to authenticate the feed in the follow maven task. for the server id in the temp settings.xml file created above is the feed name.
Turns out all I had to do was change the Agent Specification from ubuntu-18.04 to vs2017-win2016.

exclude data.sql from Spring boot jar

I am trying to exclude my data.sql and schema.sql from the Spring boot application jar.
So far I have tried several options but they do not seem to work. This is my POM configuration.
<profiles>
<profile>
<id>dev</id>
<properties>
<activatedProperties>dev</activatedProperties>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<activatedProperties>prod</activatedProperties>
</properties>
<build>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
<excludes>
<exclude>data.sql</exclude>
<exclude>schema.sql</exclude>
</excludes>
</resource>
</resources>
</build>
</profile>
</profiles>
Spring Boot enables it by default and loads SQL from the standard locations schema.sql and data.sql.If you want to disable this you can try,
spring.datasource.initialize=false
in application.properties or if you want to change default scheme or data scripts locations you can do it with,
spring.datasource.schema=
spring.datasource.data=
You can write this annotation on top of your test method
#TestPropertySource(locations = "classpath:application-test.properties")
Your application-test.properties should have something like this
spring.datasource.data=classpath:/database/seed.sql

maven, xml files for different profiles

I have maven pom with 2 profiles: dev and production
I have some xml files in my project. For example persistence.xml . Settings for dev and production environments are different
I need a way to have right files in dev and production assemblies
Maybe possible to have 2 copies of each xml file and put into assemblies right one? Or maybe possible to use settings from pom file inside xml file ?
Any other ideas or best practices?
What you are looking for was already answered here: Maven: include resource file based on profile
Instead of having two files, another solution would be to use properties directly inside the properties.xml:
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.username" value="${db.username}"/>
<property name="hibernate.connection.password" value="${db.password}"/>
<property name="hibernate.connection.url" value="${db.connectionURL}/database"/>
In your pom.xml, define a value for each property for each environment:
<profile>
<id>development</id>
<properties>
<db.username>dev</db.username>
<db.password>dev_password</db.password>
<db.connectionURL>http://dev:3306/</db.connectionURL>
</properties>
</profile>
<profile>
<id>production</id>
<properties>
<db.username>prod</db.username>
<db.password>prod_password</db.password>
<db.connectionURL>http://prod:3306/</db.connectionURL>
</properties>
</profile>
You could then use filtering to enable token replacement by the right value in each environement:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
For mode details on this solution look at this page.
If you really need to have two copy of the same file, you could also use the

How to configure maven to use different log4j.properties files in different environments

I want to be able to use different log4j configuration for different environments.
In my development environment, I want to use log4j.properties (A). But when I build in Maven for the production environment, I want to use log4j.properties (B).
Please tell me how to configure this in my pom.xml?
You can use profiles to achieve the desired behavior:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>log4j</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>output_directory</outputDirectory>
<resources>
<resource>${log4j.file}</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<log4j.file>path_to_file_A</log4j.file>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<log4j.file>path_to_file_B</log4j.file>
</properties>
</profile>
</profiles>
1. in your project add 3 folders :
Your Project\src\main\resources\
\A > log4j.properties
\B > log4j.properties
\Default > log4j.properties
2. in pom.xml
<properties>
<param>Default</param>
</properties>
<build>
<resources>
<resource>
<directory>src/main/resources/${param}</directory>
</resource>
</resources>
</build>
3.
- if : mvn clean install : classpath => log4j.properties(Default)
- if : mvn clean install -Dparam=A : classpath => log4j.properties(A)
- if : mvn clean install -Dparam=B : classpath => log4j.properties(B)
> much better than using profiles is more extensible without touching the pom
You don't need the maven-resources-plugin if you have a simple environment.
In this example, log4j.properties B is the file you use for production and is in the directory src/main/java and log4j.properties A is the file you use for development and is in the directory /Users/junger/.m2/.
In your pom.xml:
<properties>
<log4j.properties.directory>src/main/java</log4j.properties.directory>
</properties>
<build>
<resources>
<resource>
<directory>${log4j.properties.directory}</directory>
<includes>
<include>log4j.properties</include>
</includes>
</resource>
</resources>
</build>
Now, in your /Users/junger/.m2/settings.xml (create one if it doesn't exist):
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<log4j.properties.directory>/Users/devuser/.m2/</log4j.properties.directory>
</properties>
</profile>
</profile>
By using this method, each developer can have a different log4j.properties directory and you keep your pom.xml clean.
Simplest way for me,
Define a system variable ENV and set its value _dev for your development env.
Where you refer this file use like this log4j${ENV}.properties
So,
In production it simply use log4j.xml and for your dev log4j_dev.xml
In order to prevent problems it would be better to create also ENV variable for production as _pro so for production log4j_pro.xml, for dev log4j_dev.xml will be used.
I believe that relying on different files than copying resource is better practice.
There is a very simple solution good for small projects with jar packaging (I haven't tested it on war packaged projects). The only disadvantage is that you have to duplicate all resources, but if your only resource is log4j.properties this is not a problem.
If you have a directory tree like this:
...
You should have the following pom:
<build>
<finalName>${project.artifactId}</finalName>
<sourceDirectory>src/</sourceDirectory>
<resources>
<resource>
<directory>${resources.path}</directory>
</resource>
</resources>
</build>
<profiles>
<profile>
<id>default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<resources.path>resources/prod</resources.path>
</properties>
</profile>
<profile>
<id>dev</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<resources.path>resources/dev</resources.path>
</properties>
</profile>
</profiles>
Then when you use dev profile log4j.properties from resources/dev is used. When you use any other profile or no profile at all then log4j.properties from resources/prod is used. So your *.jar should look like this:
Of course if you have different resources location, for example main/java/resources/..., you should specify it instead of resources/...
To some extent you can reference environment variables inside a log4j.properties to add environment dependent behavior.
e.g.
log4j.rootLogger=${rootLoggerLevel}, ${appender}

maven super pom's profile properties inheritance at child poms

at my project there is 2 profiles and each profile has one property.
But I could not use master's properties at child's resources.
Here is described clearly but it seems that there is only one pom file and the sample shown at there is not an multi-module maven project.
All I want to do is use this properties at spring level like changing the location of properties file.
<profile>
<id>p1</id>
<properties>
<properties.location>file:/apps-core1.properties</properties.location>
</properties>
</profile>
<profile>
<profile>
<id>p2</id>
<properties>
<properties.location>file:/apps-core2.properties</properties.location>
</properties>
</profile>
<profile>
and I want to use "properties.location" at every pom file I had, either main-resources or test-resources.
here is the spring usage
<context:property-placeholder location="\${properties.location}" />
i got it working with a multi-module project with:
parent pom with <modules /> config and your profiles
module pom with following config
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
see maven resources and filtering

Resources