How to switch between properties file depending on selected profile - java

We have profiles described as :
<profiles>
<!-- Local/Windows development -->
<profile>
<id>local</id>
<activation/>
<properties>
<INSTALL_MACHINE_LIST>localhost</INSTALL_MACHINE_LIST>
<COPY_MODE>local</COPY_MODE>
</properties>
</profile>
<!-- Development -->
<profile>
<id>dev</id>
<activation/>
<properties>
<INSTALL_MACHINE_LIST>dev01</INSTALL_MACHINE_LIST>
</properties>
</profile>
<!-- QA -->
<profile>
<id>qa</id>
<activation/>
<properties>
<INSTALL_MACHINE_LIST>dqa01</INSTALL_MACHINE_LIST>
</properties>
</profile>
<!-- Production -->
<profile>
<id>prod</id>
<activation/>
<properties>
<INSTALL_MACHINE_LIST>prod01</INSTALL_MACHINE_LIST>
</properties>
</profile>
</profiles>
For our test environment, we have 2 properties file (under src/main/test/resources) application-local.properties and application.properties file. The plan is to use application-local.properties in "local" profile mode ( on our development windows system) and application.properties for rest of the profile modes. In spring context (spring-context.xml), currently, we are manually switching between 2 properties file depending on what profile we are using. Looking for a way to select automatically application-local.properties for "local" profile and application.properties for any other type of profile. Is there a way to use if-then-else condition in xml based spring-context file? I tried :
<bean id="flag" class="java.lang.Boolean">
<constructor-arg value="#{ profile == 'local' ? true: false }" />
</bean>
<util:properties id="machineMetaDbProps" location="#{ flag ? 'application-local.properties' : 'application.properties' }"/>
Getting error :
Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Property or field 'profile' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?'

try naming your property files like this:
application.properties
application-prod.properties
application-test.properties
and use "-Dspring.profiles.active=test" when starting your app
https://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html#howto-change-configuration-depending-on-the-environment

Xml Config:
In XML based config, you can make properties files related to a profile accessible to Spring via:
<beans profile="local">
<context:property-placeholder
location="classpath:docker-db.properties" ignore-unresolvable="true"/>
</beans>
<beans profile="test">
<context:property-placeholder
location="classpath:test-db.properties" ignore-unresolvable="true"/>
</beans>
Java Config:
Regarding to the active profile, you can also manually feed properties file to the spring vi java config as:
#Configuration
#Profile("local")
public class LocalPropertyReader {
#Bean
public static PropertyPlaceholderConfigurer properties() {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Resource[] resources = new ClassPathResource[] {
new ClassPathResource("docker-db.properties"), new ClassPathResource("application-local.properties")
};
ppc.setLocations(resources);
ppc.setIgnoreUnresolvablePlaceholders(true);
return ppc;
}
}
#Configuration
#Profile("test")
public class ProdPropertyReader {
#Bean
public static PropertyPlaceholderConfigurer properties() {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
Resource[] resources = new ClassPathResource[] {
new ClassPathResource("test-db.properties"), new ClassPathResource("application-test.properties")
};
ppc.setLocations(resources);
ppc.setIgnoreUnresolvablePlaceholders(true);
return ppc;
}
}
Enabling Profile:
This can be done in following ways:
Using Spring context environment : ctx.getEnvironment().setActiveProfiles("local");
Using system property : System.setProperty("spring.profiles.active", "local");
Passing a system parameter at run time: -Dspring.profiles.active="local"
Enabling profile in web.xml
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>local</param-value>
</context-param>
More Info:
Load environment configurations and properties with Spring
Example

Related

Using application.properties in xml file

I am using spring boot application with appliaction.properties.
In the project there is XML file written by another company to configure Stomp, and there is hardcoded IP of the server, but I want to change those IP to take value from application.properties.
is there any way to do it?
application.properties
property.env=SLA
property.endpoint=http://172.1.1.139/router
tcmanager.xml
<tcmanager>
<channelbuilders>
<channelbuilder>
<class>com.company.tc.stomp.TcStompChannelBuilder</class>
<config>
<properties>
<property>brokerURL=[property.endpoint]</property> //this is the place
<property>login=login</property>
<property>passcode=pass</property>
</properties>
<in> [...] </in>
<out> [...]</out>
</config>
</channelbuilder>
</channelbuilders>
<processingbuilders>
<processingbuilder>
<class>com.company.tc.template.camel.MainProcessingBuilder</class>
<config>
<properties>
<property>p1=1</property>
</properties>
</config>
</processingbuilder>
</processingbuilders>
</tcmanager>

how to integrate cache2k with hibernate

How i can integrate cache2k like hibernate cache provider?
I mean in current project we use ehcache and
enable cache in next configuration hibernate.cfg.xml :
<hibernate-configuration>
<session-factory>
<!-- Cache Configurations -->
<!-- Using net.sf.ehcache.hibernate.SingletonEhCacheProvider instead of
net.sf.ehcache.hibernate.EhCacheProvider ensures the same instance
of CacheManager is referred to by both Hibernate and our JMX Agent
simpleJpaHibernateApp.agents.jmxAgent. -->
<property name="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</property>
<!-- <property name="hibernate.cache.provider_configuration">/ehcache.cfg.xml</property> -->
<property name="hibernate.cache.use_minimal_puts">false</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_structured_entries">true</property>
</session-factory>
As well we use Cache manager class:
public class AppCacheManager {
private static final Logger log = LoggerFactory.getLogger(AppCacheManager.class);
private static CacheManager manager;
#SuppressWarnings("unused")
private static AppCacheManager INSTANCE = new AppCacheManager();
private AppCacheManager() {
manager = CacheManager.getInstance();
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ManagementService.registerMBeans(manager, mBeanServer, true, true, true, true);
if (log.isInfoEnabled()) {
log.info("Cache Manager was initialized.");
log.info("Cache Regions Detected:");
String[] cacheNames = manager.getCacheNames();
for (String cacheName : cacheNames) {
log.info(" " + cacheName);
}
log.info("Cache disk store path: " + manager.getDiskStorePath());
}
}
Can i replace in hibernate-configuration net.sf.ehcache.hibernate.SingletonEhCacheProvider with some cache2k impl?
And how i should adopt AppCacheManager base on cache2k ?
Thank you!
You can use cache2k with hibernate without any additional code.
You need to add the following dependencies in your project:
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-all</artifactId>
<version>${cache2k-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.cache2k</groupId>
<artifactId>cache2k-jcache</artifactId>
<version>${cache2k-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.0</version>
</dependency>
The hibernate configuration needs to contain:
<hibernate-configuration>
<session-factory>
<property name="cache.region.factory_class">org.hibernate.cache.jcache.JCacheRegionFactory</property>
<property name="hibernate.javax.cache.provider">org.cache2k.jcache.provider.JCacheProvider</property>
<property name="hibernate.javax.cache.uri">hibernate</property>
<!-- .... rest of configuration .... -->
</session-factory>
</hibernate-configuration>
You can then add a file cache2k-hibernate.xml to the classpath which allows further configuration of the caches, for example:
<cache2k>
<version>1.0</version>
<!-- if enabled cache2k does not refuse operation in case there is
no configuration for a requested cache name -->
<ignoreMissingCacheConfiguration>true</ignoreMissingCacheConfiguration>
<defaults>
<!-- default settings for every cache -->
<cache>
<entryCapacity>100_000</entryCapacity>
</cache>
</defaults>
<caches>
<!-- reduced size for the query cache -->
<cache>
<name>org.hibernate.cache.internal.StandardQueryCache</name>
<entryCapacity>100</entryCapacity>
</cache>
</caches>
</cache2k>

Spring Boot (XML Configuration) & Jasypt Integration

My application is merely to startup an ActiveMQ broker.
I want to use XML-based configuration in Spring Boot, to make use of the XML configuration for ActiveMQ broker (referenced here).
I'm using jasypt-spring-boot-starter for my encryption needs, but it seems that the encrypted values for my passwords are not being decrypted when the XML configuration is being initialised.
No errors during startup. Just that when I try to access the broker using admin/user it will fail with error "User name [user] or password is invalid."
Main Spring Boot App Class
#Configuration
#ComponentScan
#EnableAutoConfiguration
#SpringBootApplication
#RestController
#ImportResource({"classpath:activemq.xml"})
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
Excerpt from Broker Config (activemq.xml)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core.xsd">
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="${activemq.broker.name}" dataDirectory="${activemq.broker.data}">
<plugins>
<runtimeConfigurationPlugin checkPeriod="1000" />
<simpleAuthenticationPlugin>
<users>
<authenticationUser username="admin" password="${activemq.broker.admin.password}" groups="users,admins" />
<authenticationUser username="user" password="${activemq.broker.user.password}" groups="users" />
<authenticationUser username="guest" password="${activemq.broker.guest.password}" groups="guests" />
</users>
</simpleAuthenticationPlugin>
</plugins>
...more
application.properties
jasypt.encryptor.password=thisisnotapassword
jasypt.encryptor.algorithm=PBEWITHMD5ANDTRIPLEDES
activemq.broker.admin.password=ENC(OZRghRNXYpRiiw18KD7P6Uf2Y7fOieI7)
activemq.broker.user.password=ENC(yOiHeJlh6Z+VRVmSZe//Yw==)
activemq.broker.guest.password=guest
One thing I noticed from the startup logs is that activemq.xml gets loaded before jasypt related logs appear
Loading XML bean definitions from class path resource [activemq.xml]
...some logs
String Encryptor custom Bean not found with name 'jasyptStringEncryptor'. Initializing Default String Encryptor
This can be solved by using a custom environment, as described in https://github.com/ulisesbocchio/jasypt-spring-boot:
new SpringApplicationBuilder()
.environment(new StandardEncryptableEnvironment())
.sources(Application.class).run(args);
From the README.md:
This method is useful for early access of encrypted properties on
bootstrap. While not required in most scenarios could be useful when
customizing Spring Boot's init behavior or integrating with certain
capabilities that are configured very early, such as Logging
configuration.

Overriding JPA persistence unit

I have an empty persistenceUnit in my jar file:
<persistence-unit transaction-type="JTA" name="base1">
</persistence-unit>
<persistence-unit transaction-type="JTA" name="base2">
</persistence-unit>
My idea is to replace the empty persistenceUnit by a full persistenceUnit with properties and classes in my main project, like this:
<persistence-unit name="base1" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>java:jboss/datasources/myDS</jta-data-source>
<class>br.com.myproject.MyClass</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<shared-cache-mode>NONE</shared-cache-mode>
<properties>
<property name="hibernate.hbm2ddl.auto" value="none" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="false" />
<property name="hibernate.cache.use_second_level_cache"
value="false" />
</properties>
</persistence-unit>
But when i try to start server i got the following error:
Caused by: org.jboss.as.server.deployment.DeploymentUnitProcessingException: WFLYJPA0038: Falha ao adicionar o serviço da unidade de persistência para base1
Caused by: org.jboss.msc.service.DuplicateServiceException: Service jboss.persistenceunit.myproject#base1.__FIRST_PHASE__ is already registered"}}
Is there any way to override the persistenceUnit ?
If you really need to dynamically override your persistence.xml, this might be best done during building.
my personal warning: it sounds like a configuration-hell to me and I'd rather suggest using a container-managed JNDI approach here.
But anyway:
Use 2 maven profiles.
And if you activate profile1, then persistence.xml from profile1 will be added at the right place. and if you activate profile2 persistence.xml from profile2 will be taken.
therefore use the copy-resources-mojo for maven.
https://maven.apache.org/plugins/maven-resources-plugin/examples/copy-resources.html
If just the values of parameters change, and not the whole structure,
then you can also just "filter" and replace strings during maven-processes
then you would define properties in the profiles.
https://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html
You can also add a basic persistence.xml to your project as a default file. So if no maven-profile is activated, this one will be used. (even though it might happen, that the app doesn't work as expected, if the data-resource is not configured correctly)
Spring provides an interface JpaVendorAdapter which allows to plug in any JPA vendor specific configuration through Spring Java config or XML configuration during application startup.
You can create an EntityManagerFactory instance with LocalContainerEntityManagerFactoryBean and any implementation classes of JpaVendorAdapter such as HibernateJpaVendorAdapter, EclipseLinkJpaVendorAdapter or OpenJpaVendorAdapter.
I believe you don't even need to define the empty persistence unit in persistence.xml if your application used Spring.
Below is the sample on how to create EntityManagerFactory with Spring Java config:
#Inject
private DataSource base1DataSource;
#Inject
private DataSource base2DataSource;
#Bean
public EntityManagerFactory base1EntityManagerFactory()
throws IOException, NamingException {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean containerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
containerEntityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
containerEntityManagerFactoryBean.setPackagesToScan("YOUR_PACKAGE_NAMES");
containerEntityManagerFactoryBean.setJtaDataSource(base1DataSource);
containerEntityManagerFactoryBean.setJpaProperties(loadBase1JpaProperties());
containerEntityManagerFactoryBean.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
containerEntityManagerFactoryBean.setPersistenceUnitName("base1");
containerEntityManagerFactoryBean.afterPropertiesSet();
return containerEntityManagerFactoryBean.getObject();
}
#Bean
public EntityManagerFactory base2EntityManagerFactory()
throws IOException, NamingException {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean containerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
containerEntityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
containerEntityManagerFactoryBean.setPackagesToScan("YOUR_PACKAGE_NAMES");
containerEntityManagerFactoryBean.setJtaDataSource(base2DataSource);
containerEntityManagerFactoryBean.setJpaProperties(loadBase2JpaProperties());
containerEntityManagerFactoryBean.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
containerEntityManagerFactoryBean.setPersistenceUnitName("base2");
containerEntityManagerFactoryBean.afterPropertiesSet();
return containerEntityManagerFactoryBean.getObject();
}
#Bean
public Properties loadBase1JpaProperties() throws IOException {
ClassPathResource resource = new ClassPathResource("base1-persistence.properties");
return PropertiesLoaderUtils.loadProperties(resource);
}
#Bean
public Properties loadBase2JpaProperties() throws IOException {
ClassPathResource resource = new ClassPathResource("base2-persistence.properties");
return PropertiesLoaderUtils.loadProperties(resource);
}
Please refer to the following URL for additional info on what you can override to your persistence.xml :
http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.html
I assume you want to declare your persistent unit in a superclass and you want to define the persistent unit in a explicit project. If true you could use a JNDI approch like this:
<persistence-unit name="MyPersistenceUnit"
transaction-type="JTA">
<jta-data-source>java:/myDS</jta-data-source>
<mapping-file>META-INF/orm.xml</mapping-file>
<jar-file>Persistence.jar</jar-file>
<properties>
<property name="jboss.entity.manager.jndi.name" value="java:app/applicationEntitymanager"/>
<!-- Properties for Hibernate -->
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.show_sql" value="false" />
</properties>
</persistence-unit>
on the other side you can acces the Entitymanager with:
#Resource(mappedName = "java:app/applicationEntitymanager")
protected EntityManager em;

Arquillian testing on remote server

I want to test my war file on remote server but it is not working and giving me error:
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream cannot be cast to com.itextpdf.text.pdf.codec.Base64$InputStream
I dont know what i am doing wrong.I am new to arquillian and have checked almost all the links available but still not got any solution over this..
Here is my arquillian.xml
<?xml version="1.0" encoding="UTF-8"?>
<arquillian xmlns="http://jboss.org/schema/arquillian"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<!-- Uncomment to have test archives exported to the file system for inspection -->
<!-- <engine> -->
<!-- <property name="deploymentExportPath">target/</property> -->
<!-- </engine> -->
<!-- Force the use of the Servlet 3.0 protocol with all containers, as it
is the most mature -->
<defaultProtocol type="Servlet 3.0" />
<!-- Example configuration for a remote JBoss EAP 6 instance -->
<container qualifier="jboss" default="true">
<!-- By default, arquillian will use the JBOSS_HOME environment variable.
Alternatively, the configuration below can be uncommented. -->
<configuration>
<!-- <property name="jbossHome">/opt/jboss7</property> --> <!-- <property name="managementAddress">197.242.148.253</property> <property
name="managementPort">22000</property> <property name="username"></property>
<property name="password"></property> -->
<property name="managementAddress">197.242.148.253</property>
<property name="managementPort">22000</property>
<property name="username">abc</property>
<property name="password">aabc123</property>
</configuration>
</container>
</arquillian>
This is my test class
public class ArqTest extends Arquillian{
//creates war and deploys it
#Deployment(testable = true)
public static WebArchive createNotTestableDeployment() {
final WebArchive war = ShrinkWrap.create(WebArchive.class, "USSD.war")
.addClasses(ShowConversations.class)
.addAsManifestResource(EmptyAsset.INSTANCE, ArchivePaths.create("beans.xml"));
System.out.println("deployed");
System.out.println(war.getName());
return war;
}
#RunAsClient
#Test(dataProvider = Arquillian.ARQUILLIAN_DATA_PROVIDER)
public void Test() throws IOException {
URL url = new URL("http://197.242.148.253");
InputStream is = (InputStream) url.openStream();
BufferedReader br = new BufferedReader(new
InputStreamReader(is));
String result = br.readLine();
System.out.println(result+"hello");
br.close();
}
}
Can any body provide me some help over this
Try to add at the configuration node the next property:
<property name="allowConnectingToRunningServer">true</property>
Dunno if this will solve your error but I think you need it because, if not, arquillian tries to create a new jBoss instance instead of using the remote running one.

Categories

Resources