Wutske

I'm not checking this blog anymore !

Migrating Sonar from Derby to MySQL

,

For those people who are not familiar with Sonar, it's an opensource source code analysis tool which you can use to improve the quality of your coding. By default, Sonar comes with a simple Java Derby embedded database which is great for testing it out, but with at least 8 different projects with 25.000 - 200.000 lines of code it becomes clear that using a Derby embedded database is not a good solution. Analysis of a single project takes about 1,5 hour and these projects are growing so it's obvious that we need a serious performance boost.

The great thing about Sonar is that it supports different databases by default; MySQL, DB2, PostgreSQL and MSSQL. I decided it was time to move from Derby to MySQL and so began my queeste to transfer all the data from one db to another...



It took me a while to find the great (but unfortunately not free) tool RazorSQL. This tool was one of the few ones who was able to easily make a SQL dump of a Derby database. Dumping this 500Mb large DB generated over 400.000 SQL Queries (many of them contained LOBs) and took a good two hours to complete. Using some old school
mysql -u root < dump.sql
I then tried to import the data in MySQL. Unfortunately this didn't work since RazorSQL used the Derby SQL dialect.

After a good night sleep I went back to the internet and quickly found a great tool: openDBCopy. This tool makes it easy to migrate from one database to another !
It did require some cheating tough because Derby isn't supported by default. So here's a small step-by-step guide to help you migrate your Sonar database. You can find mysql.exe and mysqldump.exe in the MySQL Workbench.
Fyi: I don't think you can ruin anything by following this guide, but everything should be done at own risk. I'm not responsible if something goes wrong.
Fyi2: this guide describes a Derby to MySQL migration for Sonar. However, it's easy to transform this guide in a x -> y migration guide for z. Feel free to do so and don't forget to mention me wink . Of course, all at own risk.

Configuring the MySQL database:
1) Execute the MySQL query you can find in Sonar\extras\database\mysql. This will set up the schema and user.
2) Change the sonar.properties file in the conf folder so that Sonar uses the MySQL database.
# Comment the 3 following lines to deactivate the default embedded database
#sonar.jdbc.url:                            jdbc:derby://localhost:1537/sonar;create=true
#sonar.jdbc.driverClassName:                org.apache.derby.jdbc.ClientDriver
#sonar.jdbc.validationQuery:                values(1)
# directory containing Derby database files. By default it's the /data directory in the sonar installation.
#sonar.embeddedDatabase.dataDir:
# derby embedded database server listening port, defaults to 1527
#sonar.derby.drda.portNumber:               1537

#----- MySQL 5.x/6.x
# Comment the embedded database and uncomment the following lines to use MySQL
sonar.jdbc.url:                            jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8
sonar.jdbc.driverClassName:                com.mysql.jdbc.Driver
sonar.jdbc.validationQuery:                select 1


3) Start Sonar and verify it is working. If Sonar is up and running then it has populated the schema for you (if not, check the log files).
4) Stop Sonar and change the sonar.properties file so that it uses the derby database (we'll need the database up and running later).
5) To prevent duplicate primary keys we'll have to dump all the data in the MySQL database. This can be done in two steps:
a)
mysqldump.exe -u root --no-data --add-drop-table --database sonar > mysql.sql

b)
mysql.exe -u root < mysql.sql


Moving the data from derby to MySQL with openDBCopy:
1) You'll need to add some libraries to the lib folder of openDBCopy:
  • derbyclient.jar
  • derbytools.jar
  • mysql.jar

You can find these libraries on the MySQL site and the Derby site or copy them from another application
2) start openDBcopy (I used v0.51rc2)
3) Plugin > Select new Plugin > copy data from a source into a destination database
4) Important step: click on * dir() and select a directory, otherwise it won't work.
5) Make sure Sonar is running (since the Derby database needs to be running) and fill in the second tab like this:

Ps. the default derby port is 1527 wink
6) Click the "apply and test" buttons, you should see the connection url appear on the bottom of the application. You'll get a pop-up only if there's a problem.
7) The next screens are just a matter of clicking on the available buttons. Leave the mapping as it is, it should work fine.
8) On the last tab, just press execute and wait for it to finish.
9) Change the sonar.properties file so it uses the MySQL database and start Sonar.

Optional steps:
These steps are optional, but might be required
  1. Update your project's pom.xml to match the new database url and driver
  2. Update Continuum integration tool (eg. Hudson)
  3. Test new builds (not realy optional I guess p )


If you forget to update the database url you'll probably get something like this (in Maven):

Embedded error: PicoLifecycleException: method 'public void org.sonar.jpa.session.AbstractDatabaseConnector.start()', instance 'org.sonar.jpa.session.DriverDatabaseConnector@168c1e1, java.lang.RuntimeException: wrapper
org.apache.derby.jdbc.ClientDriver



If everything went fine then you've successfully migrated the Sonar database from Derby to MySQL.

Fixing Windows 7 problems when deleting executablesPC Tools firewall: no more internet after uninstalling it

Comments

Unregistered user Thursday, October 20, 2011 9:20:34 AM

Marc writes: Thanks a lot! This is a great tutorial! The migration worked like a charm.

Wutske Sunday, November 6, 2011 7:49:35 PM

I'm glad I'm not the only one who tries to migrate the data smile

Unregistered user Thursday, November 24, 2011 12:05:16 PM

Saurendra writes: Thanks for this wonderful document for migrating data from Derby to MySQL data base. But I am facing a problem while performing execute button, in the last step. That is : opendbcopy.plugin.model.exception.PluginException at opendbcopy.plugin.copy.CopyMappingPlugin.execute(CopyMappingPlugin.java:305) at opendbcopy.plugin.model.DynamicPluginThread.run(DynamicPluginThread.java:115) 2011-11-24 04:57:28,571 ERROR opendbcopy.plugin.model.exception.PluginException in (FrameMain.java:199) Please give me some resolution.

Unregistered user Friday, December 16, 2011 2:27:17 AM

Di writes: Thanks, this worked! I am so amazed. Two comments: 1) You do not need to download the workbench for mysqldump.exe et al. These scripts were already in /bin of my linux distribution 2) Was bit clear from instructions that you need to click "Capture Source Model" and "Capture Destination Model" in openDbcopy. Otherwise execution will fail with an undescriptive error message.

Unregistered user Thursday, January 26, 2012 8:51:43 PM

Anonymous writes: Thanks, just what I needed. Worked like a charm.

Unregistered user Wednesday, February 1, 2012 5:00:23 PM

Perera writes: Thanks! Worked like a charm.. Sonar guys should officially link back to this article, as I am sure its going to be very useful for many! On a side note, it would be good if Sonar guys enable derby in an in-memory mode only - so that users explicitly know its not production ready - or better yet - to show a banner on the Sonar site, clearly stating its not in production mode

Unregistered user Thursday, February 9, 2012 8:59:12 AM

Kuba writes: Great post, great guide - worked like a charm!

Wutske Thursday, February 16, 2012 6:11:43 PM

I've already tweeted the guys at Sonar the they should mention it more clearely on their site (it's already mentioned somewhere, but they did not state that the performance impact is this hughe).

Feel free to suggest it anyway wink

Unregistered user Monday, March 5, 2012 12:26:53 PM

V V S Sunkar writes: Indeed a wonderful article. Works very well.

Unregistered user Friday, March 9, 2012 11:12:22 PM

Vasee writes: Thanks for listing the steps for migrating from derby to mysql.

Unregistered user Tuesday, March 20, 2012 9:48:40 AM

srinath writes: I tried to migrate from debry to sonar. Tried modifying the property file in sonar and started the server and got the below error: Please help on this 2012.03.20 02:18:08 ERROR o.s.s.p.Platform Can not start Sonar org.picocontainer.PicoLifecycleException: PicoLifecycleException: method 'public void org.sonar.jpa.session.DefaultDatabaseConnector.start()', instance 'org.sonar.jpa.session.DefaultDatabaseConnector@60a415a3, java.lang.RuntimeException: wrapper at org.picocontainer.monitors.NullComponentMonitor.lifecycleInvocationFailed(NullComponentMonitor.java:77) ~[picocontainer-2.10.2.jar:na] at org.picocontainer.lifecycle.ReflectionLifecycleStrategy.monitorAndThrowReflectionLifecycleException(ReflectionLifecycleStrategy.java:132) ~[picocontainer-2.10.2.jar:na] at org.picocontainer.lifecycle.ReflectionLifecycleStrategy.invokeMethod(ReflectionLifecycleStrategy.java:115) ~[picocontainer-2.10.2.jar:na] at org.picocontainer.lifecycle.ReflectionLifecycleStrategy.start(ReflectionLifecycleStrategy.java:89) ~[picocontainer-2.10.2.jar:na] at org.picocontainer.injectors.AbstractInjectionFactory$LifecycleAdapter.start(AbstractInjectionFactory.java:84) ~[picocontainer-2.10.2.jar:na] at org.picocontainer.behaviors.AbstractBehavior.start(AbstractBehavior.java:169) ~[picocontainer-2.10.2.jar:na] at org.picocontainer.behaviors.Stored$RealComponentLifecycle.start(Stored.java:132) ~[picocontainer-2.10.2.jar:na] at org.picocontainer.behaviors.Stored.start(Stored.java:110) ~[picocontainer-2.10.2.jar:na] at org.picocontainer.DefaultPicoContainer.potentiallyStartAdapter(DefaultPicoContainer.java:996) ~[picocontainer-2.10.2.jar:na] at org.picocontainer.DefaultPicoContainer.startAdapters(DefaultPicoContainer.java:989) ~[picocontainer-2.10.2.jar:na] at org.picocontainer.DefaultPicoContainer.start(DefaultPicoContainer.java:746) ~[picocontainer-2.10.2.jar:na] at org.sonar.api.platform.ComponentContainer.startComponents(ComponentContainer.java:70) ~[sonar-plugin-api-2.13.1.jar:na] at org.sonar.server.platform.Platform.startDatabaseConnectors(Platform.java:142) ~[classes/:na] at org.sonar.server.platform.Platform.init(Platform.java:101) ~[classes/:na] at org.sonar.server.platform.PlatformLifecycleListener.contextInitialized(PlatformLifecycleListener.java:32) [classes/:na] at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:548) [jetty-6.1.25.jar:6.1.25] at org.mortbay.jetty.servlet.Context.startContext(Context.java:136) [jetty-6.1.25.jar:6.1.25] at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1272) [jetty-6.1.25.jar:6.1.25] at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517) [jetty-6.1.25.jar:6.1.25] at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:489) [jetty-6.1.25.jar:6.1.25] at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) [jetty-util-6.1.25.jar:6.1.25] at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130) [jetty-6.1.25.jar:6.1.25] at org.mortbay.jetty.Server.doStart(Server.java:224) [jetty-6.1.25.jar:6.1.25] at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) [jetty-util-6.1.25.jar:6.1.25] at org.sonar.application.JettyEmbedder.start(JettyEmbedder.java:79) [sonar-application-2.13.1.jar:na] at org.sonar.application.StartServer.main(StartServer.java:50) [sonar-application-2.13.1.jar:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_31] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_31] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_31] at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_31] at org.tanukisoftware.wrapper.WrapperSimpleApp.run(WrapperSimpleApp.java:240) [wrapper-3.2.3.jar:3.2.3] at java.lang.Thread.run(Thread.java:662) [na:1.6.0_31] Caused by: java.lang.RuntimeException: wrapper at org.picocontainer.lifecycle.ReflectionLifecycleStrategy.monitorAndThrowReflectionLifecycleException(ReflectionLifecycleStrategy.java:130) ~[picocontainer-2.10.2.jar:na] ... 30 common frames omitted Caused by: org.sonar.jpa.session.DatabaseException: Cannot open connection to database: Cannot create PoolableConnectionFactory (Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.) at org.sonar.jpa.session.AbstractDatabaseConnector.testConnection(AbstractDatabaseConnector.java:127) ~[sonar-core-2.13.1.jar:na] at org.sonar.jpa.session.AbstractDatabaseConnector.start(AbstractDatabaseConnector.java:70) ~[sonar-core-2.13.1.jar:na] at org.sonar.jpa.session.DefaultDatabaseConnector.start(DefaultDatabaseConnector.java:51) ~[sonar-core-2.13.1.jar:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_31] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_31] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_31] at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_31] at org.picocontainer.lifecycle.ReflectionLifecycleStrategy.invokeMethod(ReflectionLifecycleStrategy.java:110) ~[picocontainer-2.10.2.jar:na] ... 29 common frames omitted Caused by: org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.) at org.apache.commons.dbcp.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:1549) ~[commons-dbcp-1.3.jar:1.3] at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1388) ~[commons-dbcp-1.3.jar:1.3] at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044) ~[commons-dbcp-1.3.jar:1.3] at org.sonar.jpa.session.DefaultDatabaseConnector.getConnection(DefaultDatabaseConnector.java:64) ~[sonar-core-2.13.1.jar:na] at org.sonar.jpa.session.AbstractDatabaseConnector.testConnection(AbstractDatabaseConnector.java:123) ~[sonar-core-2.13.1.jar:na] ... 36 common frames omitted Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.6.0_31] at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) ~[na:1.6.0_31] at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) ~[na:1.6.0_31] at java.lang.reflect.Constructor.newInstance(Constructor.java:513) ~[na:1.6.0_31] at com.mysql.jdbc.Util.handleNewInstance(Util.java:409) ~[mysql-connector-java-5.1.13.jar:na] at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1118) ~[mysql-connector-java-5.1.13.jar:na] at com.mysql.jdbc.MysqlIO.(MysqlIO.java:343) ~[mysql-connector-java-5.1.13.jar:na] at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2308) ~[mysql-connector-java-5.1.13.jar:na] at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2122) ~[mysql-connector-java-5.1.13.jar:na] at com.mysql.jdbc.ConnectionImpl.(ConnectionImpl.java:774) ~[mysql-connector-java-5.1.13.jar:na] at com.mysql.jdbc.JDBC4Connection.(JDBC4Connection.java:49) ~[mysql-connector-java-5.1.13.jar:na] at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.6.0_31] at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) ~[na:1.6.0_31] at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) ~[na:1.6.0_31] at java.lang.reflect.Constructor.newInstance(Constructor.java:513) ~[na:1.6.0_31] at com.mysql.jdbc.Util.handleNewInstance(Util.java:409) ~[mysql-connector-java-5.1.13.jar:na] at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:375) ~[mysql-connector-java-5.1.13.jar:na] at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:289) ~[mysql-connector-java-5.1.13.jar:na] at org.apache.commons.dbcp.DriverConnectionFactory.createConnection(DriverConnectionFactory.java:38) ~[commons-dbcp-1.3.jar:1.3] at org.apache.commons.dbcp.PoolableConnectionFactory.makeObject(PoolableConnectionFactory.java:582) ~[commons-dbcp-1.3.jar:1.3] at org.apache.commons.dbcp.BasicDataSource.validateConnectionFactory(BasicDataSource.java:1556) ~[commons-dbcp-1.3.jar:1.3] at org.apache.commons.dbcp.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:1545) ~[commons-dbcp-1.3.jar:1.3] ... 40 common frames omitted Caused by: java.net.ConnectException: Connection refused at java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:1.6.0_31] at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351) ~[na:1.6.0_31] at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213) ~[na:1.6.0_31] at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200) ~[na:1.6.0_31] at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366) ~[na:1.6.0_31] at java.net.Socket.connect(Socket.java:529) ~[na:1.6.0_31] at java.net.Socket.connect(Socket.java:478) ~[na:1.6.0_31] at java.net.Socket.(Socket.java:375) ~[na:1.6.0_31] at java.net.Socket.(Socket.java:218) ~[na:1.6.0_31] at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:256) ~[mysql-connector-java-5.1.13.jar:na] at com.mysql.jdbc.MysqlIO.(MysqlIO.java:292) ~[mysql-connector-java-5.1.13.jar:na] ... 55 common frames omitted

Wutske Saturday, April 7, 2012 8:50:10 PM

Originally posted by anonymous:

srinath writes:

I tried to migrate from debry to sonar. Tried modifying the property file in sonar and started the server and got the below error: Please help on this

2012.03.20 02:18:08 ERROR o.s.s.p.Platform Can not start Sonar<br/...

If your MySQL server is not running on the same machine as Sonar (thus not connecting to localhost), you have to ensure that you grant the user 'sonar' the rights so make a connection from an external system. If it's running localhost, it's not a bad idea the check the user rights too wink .

Unregistered user Friday, April 13, 2012 10:25:00 AM

Pedro writes: Thanks, really useful stuff!

Write a comment

New comments have been disabled for this post.