As being develop a big project using Spring and maven. However there will be different environments to be deployed such as dev, test, staging and production.
The project is having a lot of different properties for different environments.
Are there any elegant way to solve this kind of thing, so I can use this as a template and reuse in other projects.
I guess spring features such as profile, placeholders and etc will be used.
Are there any good tutorial or some blog for me to get a better solution for that?
The Maven concept profile can be your friend :
<profile>
<id>DEV</id>
<build>
<resources>
<resource>
<directory>src/test/dev-resources</directory>
</resource>
<resource>
<directory>src/main/dev-resources</directory>
</resource>
</resources>
</build>
</profile>
<profile>
<id>STAGING</id>
<build>
<resources>
<resource>
<directory>src/test/staging-resources</directory>
</resource>
<resource>
<directory>src/main/staging-resources</directory>
</resource>
</resources>
</build>
</profile>
and run all your Maven build with "-P DEV" for dev propose and "-P STAGING" for staging propose for example .
You can use property configurer. Something like this:
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true"/>
<property name="locations">
<list>
<value>file:${catalina.home}/conf/your_props.properties</value>
</list>
</property>
</bean>
And you can put your properties (in this case Tomcat servlet container is used) under some config directory in each different environment.
In this case properties are stored under ${catalina.home}/conf where catalina.home refers to Tomcat's installation directory.
Related
In pom.xml, I define a property:
<profile>
<id>local</id>
<properties>
<build.profile.id>local</build.profile.id>
<serverBaseUrl>http://127.0.0.1:8080</serverBaseUrl>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
And the serverBaseUrl was referenced in file application-email.xml:
<bean id="MailService" class="someclass">
<property name="aurl" value="${serverBaseUrl}"/>
</bean>
I expect that, when running test, using IntelliJ IDEA or using Maven test, ${serverBaseUrl} can be pick up from pom.xml automatically. However, it does not work like what I expect.
When not running test, the thing works exactly what I expect.
What's the problem here? Does maven or IntelliJ IDEA won't pick up profile properties when running test by default? How can I pick up profile's properties when I running the test?
Currently, I have a workaround: Define serverBaseUrl=xxx in config.properties and the property is picked up. This is a little ugly what I want to avoid.
This is more like a shot in the dark, I could not test it.
Add the resources tag in the build section of your pom.xml:
<build>
.....
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
<includes>
<include>application-email.xml</include>
</includes>
</testResource>
</testResources>
....
</build>
I suppose your application-email.xml is inside src/test/resources folder.
I use Maven for building and would like to use logback-debugging.xml for developing but package another , logback-info.xml, to the final product.
I came up with the following Maven configuration:
<profile>
<id>development</id>
<activation>
<property>
<name>dev</name>
</property>
</activation>
<build>
<resources>
<resource>
<filtering>true</filtering><!-- if it is neccessary -->
<directory>src/main/logging/develop</directory><!-- from -->
<targetPath>${project.build.outputDirectory}</targetPath><!-- to -->
<includes><!-- what -->
<include>logback.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
</build>
</profile>
</profiles>
In Maven settings file, we can activate one profile per default:
<settings>
[..]
<activeProfiles>
<activeProfile>development</activeProfile>
</activeProfiles>
[..]
</settings>
Another way is to move the default profile configuration to the "normal" pom build section.
To activate the development profile, pass the debug flag via command line, e.g. mvn package -Ddev
Logback searches for configuration files in a specific order (see the docs here). The first place it looks is for a file called logback-test.xml in your classpath. Since you're using maven, include that file in your test/resources directory. That way when you're running any of your tests, the logback-test.xml file is used. For your production code, include logback.xml in your main/resources directory.
Is there a way to create a custom services file within META-INF/services with Maven? This is how you would do it with Ant: https://ant.apache.org/manual/Tasks/jar.html
I understand that it's possible to simply create a resources/META-INF/ in my source code and place whatever services file I want in there. Maven will then automatically pull those files into my JAR. This does not solve my issue.
The contents of my service file changes depending on the type of JAR I'm building, so I can't simply create it in my source code folders.
Having multiple versions of the service file in my source code, to have Maven exclude the ones I don't need, also doesn't solve my issue. This is because the service file needs to be a specific name; having multiple versions of the file will prevent this.
Summary: Is there a way to create the contents of a service file (META-INF/services) with Maven?
Thanks!
If you can create a reasonably low number of such service files you could store them in a separate path in your project. For example:
Then you can selectively include the files with an pom.xml like this (one more example that pom.xml is powerful, but verbose):
<properties>
<service.declaration.dir>src/serviceManifests</service.declaration.dir>
<service.files.path>META-INF/services</service.files.path>
</properties>
<profiles>
<profile>
<id>foo</id>
<build>
<resources>
<resource>
<directory>${service.declaration.dir}</directory>
<includes>
<include>${service.files.path}/foo</include>
</includes>
</resource>
</resources>
</build>
</profile>
<profile>
<id>bar</id>
<build>
<resources>
<resource>
<directory>${service.declaration.dir}</directory>
<includes>
<include>${service.files.path}/bar</include>
</includes>
</resource>
</resources>
</build>
</profile>
</profiles>
To include both files you will then run:
mvn clean package -P foo -P bar
To only include the foo file, you will run:
mvn clean package -P foo
I have Date base project as snapshot in nexus server which is using as dependency in my two web projects(test and production). but I am using two different databases for those two web projects. I want to use test data base for test web project and production data base for production web project. So I want to change hibernate configuration file path based on web project when the project is building in jenkins. My code snippet like this.
DBUtil.java
public class DBUtils {
private static SessionFactory sessionFactory;
private DBUtils() {
}
static {
Configuration configuration = new Configuration();
configuration.configure("/hibenateconfigpath");
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
pom.xml
<repositories>
<repository>
<id>snapshots</id>
<name>Snapshots</name>
<url>url/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.my</groupId>
<artifactId>DBAccess</artifactId>
<version>0.0002-SNAPSHOT</version>
</dependency>
Please provide any solution to this with maven profiles or what ever it is.
You can use maven profiles to build your project. You have to define the profiles in your pom.xml:
<profiles>
<profile>
<id>test</id>
<properties>
<db.driverClass>com.mysql.jdbc.Driver</db.driverClass>
<db.jdbcUrl>jdbc:mysql://xxxxx:3306/test</db.jdbcUrl>
<db.user>test-user</db.user>
<db.password>test-pass</db.password>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<db.driverClass>com.mysql.jdbc.Driver</db.driverClass>
<db.jdbcUrl>jdbc:mysql://yyyyy:3306/prod</db.jdbcUrl>
<db.user>prod-user</db.user>
<db.password>prod-pass</db.password>
</properties>
</profile>
</profiles>
In hibernate.cfg.xml file you can use the defined properties like this:
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">${db.driverClass}</property>
<property name="connection.url">${db.jdbcUrl}</property>
<property name="connection.username">${db.user}</property>
<property name="connection.password">${db.password}</property>
</session-factory>
</hibernate-configuration>
Then, you have to configure your build section in pom.xml:
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<warName>${project.artifactId}</warName>
<webResources>
<resource>
<filtering>true</filtering> <!-- THIS IS IMPORTANT! It tells maven to replace your variables with the properties values -->
<directory>src/main/webapp</directory>
<includes>
<include>**/hibernate.cfg.xml</include> <!-- the path to hibernate.cfg.xml -->
</includes>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
Then you can call mvn clean install -Pdev|prod.
You can also tell jenkins which profile you wish to build in the maven configuration.
create a property file and when your going to start building the project using jenkins, write a bash script to access the property file from your source code and change your desired configuration regarding your build plan (Production, Test).
after your maven build your source code, desired output will be provided.
if your jdbc database jar is wrapped inside another jar and that jar exist inside your nexus server, you should go to the wrapping project source first add your other database jar jdbc dependencies in there, then deploy the project into the nexus again.
when the new version of wrapped jar was provided, you can decide which database you wish to connect using the above explanation with changing these properties using your written bash script (you have to go inside your jenkins and write this bash script before your maven clean install deploy plan start):
hibernate.connection.driver_class (ex: com.mysql.jdbc.Driver)
hibernate.connection.url property (ex: jdbc:mysql://localhost:3306/mehdi)
hibernate.dialect property (ex: org.hibernate.dialect.MySQLDialect)
and because this will make your project to use specific config regarding your plans (Test, Production), even if there be different jdbc drivers jars within your wrapped jar file, It does not create any conflict and problem because each database have different property configs.
I'm working on a modular maven project. The skeleton of my project is the following:
|-- parent
|-- model
--pom.xml
|-- services
--pom.xml
|-- web-app
--pom.xml
In the model module I have the persistence.xml file with some property references:
<persistence>
<persistence-unit name="myUnit">
//Some classes definition
<properties>
<property name="javax.persistence.jdbc.driver" value="${db.driverClass}" />
<property name="javax.persistence.jdbc.url" value="${db.connectionURL}" />
<property name="javax.persistence.jdbc.user" value="${db.username}" />
<property name="javax.persistence.jdbc.password" value="${db.password}" />
</properties>
</persistence-unit>
and I enable the resources filtering in the model's pom.xml through
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
Now I should want to define a profile in the web-app's pom.xml
<profiles>
<profile>
<id>Development</id>
<properties>
<db.driverClass>MyDriver</db.driverClass>
<db.connectionURL>jMyUrl</db.connectionURL>
<db.username>MyUsername</db.username>
<db.password>MyPassword</db.password>
</properties>
</profile>
</profiles>
<!-- To launch embded jetty server -->
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${maven-jetty-plugin.version}</version>
</plugin>
and replacement the references with the values when I run "mvn jetty:run -P Development".
But this not work.
How can I do to solve it?
Maven uses a hierarchical approach.
This means that profiles are only active in the module they are defined and their children. Same goes for properties.
In your case, your file to filter is in a sibling module of the one you are defining the properties. Therefore they are not propagated to the model module
mvn jetty:run does not copy your resources, and thus does not filter. It is mainly designed to work in conjunction with an IDE, i.e. you change something, the IDE compiles/copies your changes.
If you call it from the console, you need to explicitly run the lifecycle (or at least the process-resources phasein your case).
So try something like
mvn process-classes jetty:run
Ideally, you could split the execution into two separate shells, one running jetty:run and the other running mvn process-classes on demand.
Or use an IDE.