Spring Hibernate - Set static final String to indicate the schema of Hibernate entity - spring

I have domain objects mapped as Hibernate entities stored in 2 distinct schemas of an Oracle database. Unfortunately, one of this schema has not the same name between Test and Prod environment database.
To avoid changing manually the schema in the code each time I deploy on such or such environment, my idea was to use a Spring property placeholder to get values in a properties file depending of the environment. Then using MethodInvokingFactoryBean to set those properties in useful static Utility class.
Spring's conf setting values of static variables depending of properties read in a properties file with Spring's PropertyPlaceholderConfigurer :
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="com.company.app.Schemas" />
<property name="targetMethod" value="setSchemaNames" />
<property name="arguments">
<props>
<prop key="schema1">${schema1_name}</prop>
<prop key="schema2">${schema2_name}</prop>
</props>
</property>
</bean>
Then class hosting static schemas names :
public class Schemas {
public static String SCHEMA1;
public static String SCHEMA2;
public static void setSchemaNames(Map<String, String> schemaNames) {
Schemas.SCHEMA1 = schemaNames.get("schema1");
Schemas.SCHEMA2 = schemaNames.get("schema2");
}
}
Fianlly Hibenate mapping :
#Entity
#Table(schema = Schemas.SCHEMA1, name = "item")
public class Item {
...
}
However to set the schema attribute of the #Table Hibernate annotation, I cannot use "static" variables, I must use "final static" variables (constant). So the last piece of code above does not compile.
I did not succeed to set "final static" variable with Spring's MethodInvokingFactoryBean. How could I do ?

In theory you could create a class which accesses the public static final fields and us reflection to make them accessible and set the value.
Field field = ReflectionUtils.findField(Schemas.class, "SCHEMA1");
field.setAccessible(true);
ReflectionUtils.setField(field, target, "MySchema");
However even with that in place it will never work. The constants in the Item class will be inlined, at compile time, with the actual value. If you would decompile your Item class it would look something like the following.
#Entity
#Table(schema = null, name = "item")
public class Item {
...
}
That is simply the way constants work in java (or better the java compiler).
I have domain objects mapped as Hibernate entities stored in 2 distinct schemas of an Oracle database. Unfortunately, one of this schema has not the same name between Test and Prod environment database
This might help you in your solution. Basically in your entities which have the constant schema in test en prod define the schema. For the other entities (different schema in test en prod) don't define a schema but simply set the hibernate.default_schema property in your configuration.

Related

How do you create a subclass of PropertySourcesPropertyResolver in spring 4?

I'm trying to figure out a way to store certain properties in an encrypted form while they are at rest, and have them transparently decrypted before the property is injected into any beans, whether they are using #Value or they are defined in xml by setting properties. We're not using spring-boot yet. The property file would look like this:
db_password={aes}some_encrypted_value
I can see in the logs where the PropertySourcesPropertyResolver gets the value for my property. It should be pretty simple to create my own implementation of the PropertySourcesPropertyResolver.getProperty method that looks for the "{aes}" prefix, decrypting it if necessary, but I can't figure out how to use my subclass in my application.
Does anyone have any idea how I can get spring to use my implementation instead of Springs?
I initially tried to use the PropertySourcesPlaceholderConfigurer that worked for me in Spring 3, but I couldn't figure out how to make it work in spring 4. I also couldn't get the newer PropertySourcesPlaceholderConfigurer to work either.
Can anyone point me in the right direction?
We did it as follows with Spring 4.0.3 RELEASE
public class MyPropertyConfigurer extends PropertyPlaceHolderConfigurer{
protected void convertProperties(Properties props){
Enumeration<?> propertyNames = props.propertyNames();
while(propertyNames.hasMoreElements()){
String propName = (String)propertyNames.nextElement();
String propValue = (String)props.getProperty(propName);
if(propName.indexOf("db_password") != -1){
setPropertyValue(props,propName,propValue);
}
}
}
private void setPropertyValue(Properties props,String propName,String propValue){
String decryptedValue = PasswordUtility.decrypt(propValue);
props.setProperty(propName,decryptedValue);
}
}
In xml, it was configured as below
<bean id="dbPropertyPlaceholder" class="mypackage.MyPropertyConfigurer">
<property name="locations">
<list>
<value>file:myProp.properties</value>
<list>
</property>
</bean>

Configurable number of Spring DAO objects

I have an app that access a configurable list of databases. I do not want to hardcode the corresponding DAO objects in the class. Is there a way to do that in Spring?
The hardcoded way would be:
databases.properties:
db1.url = jdbc://db1.acess.com:3306
...
db2.url = jdbc://db2.access.com:3306
...
db3.url = ldap://ldapdb.access.com:3306
applicationContext.xml:
<bean id="MyServicebean" class="com.MyServiceImpl">
<property name="DBDao1" ref="DBDao1"/>
<property name="DBDao2" ref="DBDao2"/>
<property name="LdapDao" ref="LdapDao"/>
</bean>
public class MyServiceImpl {
#Autowired
private DBDao DBDao1;
#Autowired
private DBDao DBDao2;
#Autowired
private LdapDao LdapDao;
...
}
Is there a more flexible way of configuring and autowiring DAO objects based on how many DBs we specify in databases.properties?
Looking at your database.properties, it seems not all DAOs are connecting to Databases. Some are connecting to LDAP server. So obviously implementation of DAOs will be different and can't generalize/abstract it.
If all DAOs that connect to databases perform the same set of operations and connects to different databases based on some criteria (ex: clientId) then take a look at Spring's AbstractRoutingDataSource. http://spring.io/blog/2007/01/23/dynamic-datasource-routing/

Call certain methods alone in a class using spring/pojo?

I am implementing a health check for my application.I have configured the classes for different logical systems in our application and have written methods which check for conditions across the environment like db count , logging errors , cpu process etc.
Now I have requirement where I have to check only certain conditions ie certain methods in the class according to the host.
What is the best way to access those methods via property file ? Please give your suggestions.
Thanks.
I don't like using reflection for this sort of thing. Its too easy for the property files to be changed and then the system starts generating funky error messages.
I prefer something straightforward like:
controlCheck.properties:
dbCount=true
logger=false
cpuProcess=true
Then the code is sort of like this (not real code):
Properties props = ... read property file
boolean isDbCount = getBoolean(props, "dbCount"); // returns false if prop not found
... repeat for all others ...
CheckUtilities.message("Version " + version); // Be sure status show version of this code.
if (isDbCount) {
CheckUtilities.checkDbCount(); // logs all statuses
}
if (... other properties one by one ...) {
... run the corresponding check ...
}
There are lots of ways to do it but this is simple and pretty much foolproof. All the configuration takes place in one properties file and all the code is in one place and easy for a Java programmer to comment out tests that are not relevant or to add new tests. If you add a new test, it doesn't automatically get run everywhere so you can roll it out on your own schedule and you can add a new test with a simple shell script, if you like that.
If its not running a particular test when you think it should, there's only two things to check:
Is it in the properties file?
Is the version of the code correct?
You can define different beans for every check you need:
<bean id="dbcountBean" class="DBCountHealtCheck" scope="prototype">
<!-- bean properties -->
</bean>
Then a bean for HealtCheck with operations bean injected:
<bean id="healtChecker" class="HealtChecker" scope="prototype">
<property name="activeChecker"><bean class="PropertiesFactoryBean>
<property name="location">file:path/to/file</property></bean>
</property>
<property name="dbCountCheck" ref="dbCountBean" />
<!-- other properties -->
</bean>
class HealtChecker {
private DBCountHealtCheck dbCountChecker;
private Properties activeChecker;
public void setDbcount(DBCountHealtCheck dbCountChecker) {
this.dbCountChecker = dbCountChecker;
}
public void setActiveChecker(Properties activeChecker) {
this.activeChecker = activeChecker;
}
public void check() {
if("true".equals(this.activeChecker.get("dbCount")) {
this.dbCountChecker.check();
}
}
If with this solution you can't reload file, in HealthChecker remove activeChecker a property public void setPropertiesLocation(URL propertiesLocation); let HealthChecker implements InitializingBean and load properties in afterPropertiesSet()

mybatis 3.1 + sprinng 3.2 properties

We have 4 applications running on a Tomcat7 server. The existing applications work on Hibernate and Spring.
The backend is connected to a second database and some old schemas are kept here live. Each schema is called xxx_live and xxx_test.
When the Tomcat server starts, a JNDI property is set for the right environment.
Test
Local
Live
The properties are parsed on an extention of the PropertySourcesPlaceholderConfigurer class:
public class GenericPropertySourcesPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer {
private String application;
private String environment;
private static final String ENVIRONMENT = "environment";
public GenericPropertySourcesPlaceholderConfigurer(String application) throws IOException {
this.application = application;
this.environment = System.getProperty(ENVIRONMENT);
if (this.environment == null) {
this.environment = System.getenv().get(ENVIRONMENT);
}
initPropertySources();
}
/**
* setup default properties configuration
* Default configuration properties look like :
* app-global.properties
* app-environment.properties
* jndi properties
*/
private void initPropertySources() throws IOException {
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addLast(new ResourcePropertySource(new ClassPathResource(MessageFormat.format("properties/{0}-global.properties", application))));
propertySources.addLast(new ResourcePropertySource(new ClassPathResource(MessageFormat.format("properties/{0}/{1}.properties", environment, application))));
propertySources.addLast(new NotFailingJndiPropertySource("jndi"));
setPropertySources(propertySources);
setIgnoreResourceNotFound(false);
setIgnoreUnresolvablePlaceholders(true);
}
}
Now we're migrating everything to MyBatis. Is there a way to inject or parse these properties into my XML configuration?
Something like:
<select id="findAllUsers" parameterType="list" resultType="user">
SELECT * FROM ${mybatis.default_schema}.USER
</select>
Yes, Definitely you can pass this property.
The function declaration in DAO layer (JAVA Mapper for mybatis in spring) would be like
List<User> findAllUsers(#Param("schemaName") String schemaName)
And when you call this function pass the schema name as argument.
Few Suggestions (Assuming you are new to MyBatis)
You should rather configure your Property using spring's util tag in context.xml
i.e. <util:properties id="mailProps" location="classpath:mail.properties" />
Scan for Mappers & Autowire using spring (again in context.xml)
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.foo.bar" />
</bean>
Where com.foo.bar is package where you Java Interface's representing your XML are located.
This way You will actually be using spring's benefits i.e. DI / IOC
parameterType would be String or java.lang.String not list.
If you need further help / any doubts feel free to ask back.
HTH
Thanks.

Inject Dynamic Values for the property in Spring

I am very new to Spring and while going through the DI topic through various sources (Book & Internet) I have seen the following pattern of defining bean configuration:
For example we have a class "SampleApp"
public class SampleApp
{
private int intValue;
private float floatValue;
public SampleApp(int value)
{
intValue = value;
}
public void setIntValue(int value)
{
intValue = value;
}
public void setFloatValue(float floatValue)
{
this.floatValue = floatValue;
}
}
Corresponding bean configuration is as follows:
<bean class="somepackage.SampleApp" id="samplebeanapp">
<constructor-arg value="15" />
<property value="0.5" name="floatValue"></property>
</bean>
We have been hard-coding the value here to 15 & 0.5.
Here are my questions :
Is it possible to pass those values as run time parameter with scope as prototype?
If yes, how can we do it? and please elaborate with some example.
Spring configuration files are processed at startup, and Spring singleton beans are instantiated too in that moment. They are not processed again during the application lifecycle, in normal conditions.
You can use such type of property injection to pass configuration values, while you can use injection of object references to determine the structure of your application.
To avoid hardcoding the values inside the XML files, you can extract them in property files using a PropertyPlaceholderConfigurer.
The principle is to program to interfaces as much as possible, so you don't tie yourself to any specific implementation. However, for the case you're thinking, you'll just pass the values at runtime.
Example: BeanA needs the services of DaoBean, but the DaoBean won't be instantiated by BeanA. It will be passed to BeanA through dependency injection and BeanA will only talk to a DaoInterface.
At this point if BeanA want to save 15 and 0.5, will call the methods with the actual values (or more commonly variables).
daoInterface.saveInt(15);
daoInterface.saveFloat(0.5);
I don't use dependency injection to pass the values in this case. Dependency injection is a great tool, but doesn't meant that it has to be used everywhere.

Resources