Sunday, March 29, 2015

AmbiguousTableNameException and NoPrimaryKeyException from DBUnit

Recently I wrote some JUnit tests with DBUnit. The first problem encountered was the exception:

org.dbunit.database.AmbiguousTableNameException: INFOCODE.

 Looking into the DBUnit source code, I figured out that actually INFOCODE is a table name in my database and DBUnit thought that there were more than one tables with that same name. (The database is large and I am not familiar with all tables. So my first though was that INFOCODE is a code used by DBUnit to tell something. It is worth of pointing out that my unit tests and the code to be tested never access the INFOCODE table.) If the exception were named DuplicatedTableNameException, it would help more to figure out the problem sooner. Then it came up to me that my database has multiple schemata and some of them have a table with identical name. Searching DBUnit documentation yielded a solution: passing the desired schema name as an argument to the DatabaseConnection constructor.

 IDatabaseConnection connection = new DatabaseConnection(sqlConnection,  schemaName); 

 where sqlConnection is a javas.sql.Connection, and schemaName is the name of the desired schema. (IDatabaseConnection is DBUnit's database connection interface)

The second problem was the exception:

org.dbunit.dataset.NoPrimaryKeyException: ACCOUNT

ACCOUNT is the name of a table that my code accesses. My database is an old one and no primary key is defined for that table. The DBUnit document does address this problem. The solution, however, is partly incorrect and lacks necessary details. Looking into the DBUnit source code helped to find the right solution:

DefaultColumnFilter columnFilter = new DefaultColumnFilter();
columnFilter.includeColumn("accountId"); // telling DBUnit to treat the named column as primary key
connection.getConfig().setProperty(DatabaseConfig.PROPERTY_PRIMARY_KEY_FILTER,  columnFilter);
where connection is a DBUnit IDatabaseConnection.

By the way, the JUnit tests do not have to extend any DBUnit class or to implement any DBUnit interface. Data can be inserted into, deleted from, and read from database using statements like:
DatabaseOperation.INSERT.execute(connection, dataSet); 
DatabaseOperation.DELETE.execute(connection, dataSet);
ITable accountTable = connection.createQueryTable("account table", "SELECT * FROM account WHERE accountId = 'myAccountId'");
where dataSet is DBUnit IDataSet.

The appendix below gives sample code to construct IDataSet from data in xml files.

Appendix – Load Data from xml Files on Classpath
public static IDataSet importData(String path) {
    InputStream iStream = instance.getClass().getClassLoader().getResourceAsStream(path);
    if (iStream == null) {
        throw new RuntimeException("In valid file path: " + path + ". The path must be on classpath.");
    InputSource inputSource = new InputSource(iStream);
    FlatXmlProducer flatXmlProducer = new FlatXmlProducer(inputSource);
    IDataSet dataSet = null;
    try {
        dataSet = new FlatXmlDataSet(flatXmlProducer);
    } catch(DataSetException e) {
        throw new RuntimeException("In valid data in file: " + path + ".");
 return dataSet;

Wednesday, March 4, 2015

Migrating a User Domain from WebLogic Server 11g to 12c

I had been running WebLogic Server 11g (i.e. 10.3.6) as a development server for a while. Recently I decided to upgrade to WebLogic Server 12c (i.e.12.1.2). The installation was easy. I however had a user domain with a couple of dozen services (e.g. data sources). It is quite tedious to manually recreate them in a newly created domain.

At first I just tried to copy the whole domain directory in WebLogic Server 11g to WebLogic Server 12c. It does not work. Then I tried to create a domain template from my WebLogic Server 11g and create a new domain in WebLogic Server 12c using that domain template. It does not work either. It turned out that domain templates from WebLogic Servers of different versions are not compatible. The way to make the “domain upgrade” is to use the WebLogic WLST tool. In short, I “exported” the server configuration from my WebLogic Server 11g, and “imported” it into my WebLogic Server 12c. The detail follows.

All examples in this article are pertinent for Windows under the following assumptions:
  • The home directory of the existing domain for WebLogic Server 11g is “C:\wl11gdomains\mydomain
  • The home directory of the new domain for WebLogic Server 12c is “C:\wl12cdomains\mydomain
  • Environment variable WL_HOME denotes the home directory of WebLogic Server 11g
  • Environment variable MW_HOME denotes the home directory of WebLogic Server 12c

“Export” Server Configuration Using WLST

Open a command window, run command:

It starts WLST, with prompt:

In the WLST shell, run command:
configToScript(‘C:/wl11gdomains/mydomain’,  'C:/wlconfig/',  'true', 'C:/wlconfig/', 'false')

It will create 4 files under C:\wlconfig
  3. c2sConfigemdevdomain
  4. c2sSecretemdevdomain

In order to import the configuration into WebLogic 12c, we need to overwrite part of the generated file (assuming the default weblogic username and password are “weblogic” and “password”):
  1. Replace “userName=” with “userName=weblogic”
  2. Replace “userName=” with “userName=weblogic”
  3. Replace “passWord=” with “passWord=password”
  4. Replace “domainDir=WLSTConfigToScriptDomain” with “domainDir=mydomain” 

If you want, you can also change the following properties:

  • adminServerName
  • domName

Install WebLogic Server 12c

Donwload the installation zip file, unzip it. The home directory will be referred to as %MW_HOME%
If not yet, install JDK 7, and set environment variable JAVA_HOME to the home of JDK 7. (WebLogic 12c required Java 7). Also set environment variable MW_HOME to the home of WebLogic 12c.

Open a command window. In the %MW_HOME%, run command:

The installation is done.

Create New WebLogic Server 12c Domain

Open a command window. cd into C:\wl12cdomains. Run command:

Then run command:

It starts the Configuration Wizard. Use the Configuration Wizard to create a new domain and server with exactly the same name for the domain (and server) as the existing ones.
The domain is created.

At this point, you may want to add some third-party jar files (eg. JDBC drivers) to C:\wl12cdomains\mydomain\lib. You may also want to modify C:\wl12cdomains\mydomain\bin\setDomainEnv.cmd and C:\wl12cdomains\mydomain\bin\startWebLogic.cmd to set various Java options (e.g. debug port)

 “Import” Server Configuration Using WLST

Start the server with this domain. (It is optional, but better)
Open a command window. cd into directory C:\wl12cdomains. Run command:

Then run command:

It starts WLST, with prompt:

In the WLST shell, run command:

It will configure the new domain with all configuration of the old domain.


Appendix - Use Configuration Wizard to Create a New Domain