Dynamically disable hbm2ddl.auto? - java

I have a eclipse workspace with many projects, one project "shareddata" contains all my jpa entities, services, persistence.xml (using spring-data) and such. In my other projects i have included "shareddata" as dependency in my maven pom.xml .
When i start one of the other projects, jpa/hibernate validates and updates my database tables (hbm2ddl.auto = true). This works nicely.
But to test my entire project in need to start several projects that all include the "shareddata" project. So every single project validates and updates my database tables. This takes quite a bit of time.
Is it possible only to enable "hbm2ddl.auto" for one single project? Or is it possible to dynamically disable "hbm2ddl.auto" at application startup?
If that is possible than i could start up my jms server project and do database validation. Next i start up my other projects (tomcat and several server apps) and they won't do the database validation.
Saves me a lot of time :-)

I did such things via system properties. Unfortunately I do not know how do you initialize hibernate context. I personally did it via Spring that supports system properties using ${propName} syntax. If you can use this notation just use it in your configuration files and set appropriate property in the beginning of your unit test.

It took a little while to figure out, but jpa is configured in my applicationContext.xml (or variations like root-context.xml). LocalContainerEntityManagerFactoryBean does the initialization.
Lucky LocalContainerEntityManagerFactoryBean accepts parameters that seem to override the values set in persistence.xml . So i set hibernate.hbm2ddl.auto to none in persistence.xml and use the following xml to enable hibernate.hbm2ddl.auto for a specific project:
<!-- Add JPA support -->
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
Hope this may help someone with the same problem.

Related

Hibernate creating Schemas on each application run?

I have built a web application using MVC pattern and Hibernate. I am trying to configure my hibernate to create schemas for my classes by using following property
<property name="hibernate.hbm2ddl.auto">create</property>
But, I found out that this drops the previous existing schema and re-creates schema on each application run. Is there anyway I configure my hibernate to create schemas only on my first application run and for any future application run just update the rows in existing database?
As YomanTaMero mentioned instead of :
<property name="hibernate.hbm2ddl.auto">create</property>
try this:
<property name="hibernate.hbm2ddl.auto">update</property>
Noticed "update" above?

How can I recreate my database with hibernate pojo files

I lost my projects' database from my pc. But I have my JSP project which includes hibernate. Whenever I run the project it says 'org.hibernate.exception.SQLGrammarException: Cannot open connection' because the database not exist in the server. Can I recreate my database with the help of the POJO files? I am using netbeans and MySQL server 5.1
Yes you can recreate your database using hibernate.
In our session factory you need to set the following property.
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
hibernate.hbm2ddl.auto Automatically validate or exports schema DDL to the database when the SessionFactory is created
There are a couple of caveats you need to understand:
This will only recreate objects which you had mapped. This process will not recreate any database object which you may have had but didn't have mapped.
Certain object names may not be named what they were previously. One classic example would be the names of your foreign-key constraints.
This will at least get you back up with a majority of what you lost at the very least.

How spring load configuration file by environment?

I use spring framework in my application,and i use some configuration files,but in different environment,i need to use different properties like db config properties.Now i put different files in different path,then i use maven profile method to package different WAR.
Now,i want to package only one WAR in all environment,and want by transfer different parameters to use different configuration files.In addition i don't want to put the configuration file out of the project.
You can use spring bean profiles or conditional beans.You can use following configuration to define propertyplaceholder beans for each environment.
<beans profile="environment1">
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>database_env1.properties</value>
</property>
</bean>
</beans>
<beans profile="environment2">
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>database_env2.properties</value>
</property>
</bean>
</beans>
For database configuration, a possible approach is to define the JDBC DataSource as a JNDI resource directly in your application server that you then use (see how) - this way your WAR file doesn't contain the connection information, the runtime environment does hold this info instead.
One advantage of this approach is that the connection information then can be managed by a server administrator instead of the application developer.
Not sure it meets your "no configuration outside project" requirement though.

Spring Boot Configuration Priority

I am working on a new project and using Spring-Boot for the first time.
Traditionally, when using Spring and property files for configuration, I provided default properties in the distribution (WAR) and allowed for overriding them in some documented place.
For example:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:app.properties</value>
<value>file:${user.home}/.company/app/app.properties</value>
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="ignoreResourceNotFound" value="true" />
</bean>
This would allow us to re-deploy the application without losing local system configurations.
After reading the documentation on this for Spring-Boot, it seems that anything in "application.properties" takes a higher priority, and overwrites, anything specified with the #PropertySource annotation.
I like Spring because it allows us to stick to convention, which concerns me that I may have been doing the properties cascading wrong.
What would be the most appropriate way to provide externalized properties, with sensible defaults (embedded database, simple authentication, etc) that are included in the distribution?
Also, if anyone knows, I would love to know the reasoning behind the order for properties in Spring-Boot.
Note
I've tried looking at SpringApplication.setDefaultProperties, but cannot seem to find where to get a reference to the SpringApplication Object. The main method calls a static method on it (run), which is never actually run when bundled as a WAR file. It also seems a little bit of a hack to do it this way.
SpringApplication is a public class so you can create an instance and set its properties before running your app (the static run() methods are just conveniences). You can also use SpringApplicationBuilder, which is what you get as a callback when you are running in an external container anyway. Using those APIs you can set default properties, and profiles, including the location (spring.config.location) and name (spring.config.name) of the application.properties file.
Note that (per the link you provided) you can also use JNDI variables in the container to override or set environment properties. That could also be useful if you are packing multiple apps into the same JVM.

WebSphere and PropertyPlaceholderConfigurer

I'm a big user of properties (with PropertyPlaceholderConfigurer) for making my application as "dynamic" as possible. Almost all the constants are defined as such. Anyway, I'm currently defining a default.properties which comes shipped with the default WAR.
In other environments (Acceptance/Production) I need to overwrite of the configurations. I'm doing this as following:
<bean id="propertyManager"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:com/company/default.properties</value>
<value>file:${COMPANY_PROPERTIES_LOCATION}\kbo-select-settings.properties</value>
</list>
</property>
</bean>
With this means I can use a promotable build for each of the environments.
HOWEVER, I do dislike the fact that I can't change any of my properties from inside WebSphere. Instead I have to go to each of the servers (we have 8 clustered) and change the properties accordingly. It would be a lot more user friendly if I could change those from inside WebSphere and just perform a restart afterwards...
Anyone has an idea on how I could do such a promotable build? I already define JNDI configuration for datasources/java mail/etc.
Thanks!
We solved this problem by using an extension on the property file for each environment (local, dev, int, tst ...) and each file contained specific values for those environments. The only addition you then require is a VM argument on the server to set -Druntime.env=X.
Your lookups in your config file will then look like this
<bean id="propertyManager"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:com/company/default.properties.${runtime.env}</value>
<value>file:${COMPANY_PROPERTIES_LOCATION}\kbo-select-settings.properties</value>
</list>
</property>
</bean>
Of course this only works if you have fairly static environments, as it still doesn't lend itself to changing it at runtime, but it does makes promotion of the application dead simple. If you want to be able to change the values without redeploying your application, you will have to have them stored outside your application, which you already seem to be doing for the kbo-select-settings.properties
One potential issue is that you are hardcoding the location of your properties file. You could specify the location of the properties file as a JNDI resource and falling back on the defaults specified on the classpath:
<!-- try to lookup the configuration from a URL, if that doesn't work, fall back to the properties on the classpath -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<bean class="org.springframework.core.io.UrlResource">
<constructor-arg>
<jee:jndi-lookup
jndi-name="url/config"
default-value="file:///tmp" /> <!-- dummy default value ensures that the URL lookup doesn't fall over if the JNDI resource isn't defined -->
</constructor-arg>
</bean>
</property>
<property name="properties">
<bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:com/company/default.properties</value>
</list>
</property>
</bean>
</property>
<property name="ignoreResourceNotFound" value="true"/>
</bean>
That way you can specify different file names for different environments using the WAS console in Resources > URL > URLs by creating a resource with the JNDI-name "url/config" and pointing it to the correct file (file:///your/path/to/properties).
As an alternative solution, if you want to manage individual properties through the console, you instead of using the PropertyPlaceholderConfigurer you could use jee:jndi-lookup to get values from the web.xml env-entries (which you can manage using the WAS console). See this answer
If the configuration is in the EAR file then I know of no simple way to propogate changes without backdoor cheats or re-deploying the app.
I think that configuration, espcially that which changes when you promote the app should not be in the application.
One approach is described here by Keys Botzum,
Note that you can actually propogate files that are not part of any particular application out to nodes using standard WebSphere synchronisation.
Another option is to use a database for config. These days poppin XML into a DB such as DB2 is not very hard.
Adding a URL resource that points to your config files to your websphere servers and then looking that up in your application is a viable way to go. You can then configure the url to point to a central location where all the configuration files are managed - if you use svn and your svn has read-only access you could even directly read them from svn (via http).
Spring has some built in facilities for this, and it also means you can priorities various config files.
For more information take a look at how-to-differentiate-between-test-and-production-properties-in-an-application
The way that I have dealt with this is to use property values on the JVM's but then reference them to a WebSphere variable that is defined at the cluser or cell level. For example, say you want a value called value1 set in param1 in your spring configuration you would do the following:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
And then something like as follows do reference the variable:
<bean id="id" class="com.blah.class">
<property name="value1" value="${param1}" />
</bean>
Then within your tests you can setup your tests as follows:
/**
* #see org.springframework.test.AbstractSingleSpringContextTests#prepareApplicationContext(org.springframework.context.support.GenericApplicationContext)
*/
#Override
protected void prepareApplicationContext(GenericApplicationContext context) {
System.setProperty("param1", "myvalue");
}
Then from within the websphere configuration, if you create a JVM variable and link it to the WebSphere variable you only need to change the WebSphere variable and it will automatically update all the JVM variables on each machine.
To do this, create a JVM variable called:
param1
with a value of ${webspherevar.param1}
And then create a WebSphere variable called:
webspherevar.param1
That contains whatever the value you need to put in it. This allows you to then not have to ship around the values for each environment and they can be instead loaded into the environment and just used.
I hope this helps.

Categories