DBUnit is very nice for testing database content changes made by an application. You define in XML the data including the structure of your tables (dataset.xml).
Simple_Data is the name of the table and each column is a attribute in the xml doc with the content value e.g. id with value 1.
The Getting Started of DBUnit work with JUnit 3.8 and self handling of the JDBC Connection.
JUnit 4.x are more comfortable with annotations based test methods and Spring comes with dependency injection for separating
configuration from implementation code.
The following approach combines DBUnit with JUnit 4.4 and Spring 2.5.6 to test comfortable a Oracle 10g database.
I use Maven 2.x to define the depending libraries used by the example (pom.xml):
4.0.0 de.schaeftlein.dev.dbunit test-dbunit test-dbunit 0.0.1-SNAPSHOT org.dbunit dbunit 2.4.2 org.springframework spring 2.5.6 jar compile junit junit 4.4 commons-dbcp commons-dbcp 1.2.2 org.springframework spring-test 2.5.6 org.slf4j slf4j-api 1.5.6 org.slf4j log4j-over-slf4j 1.5.6 log4j log4j 1.2.14 org.slf4j slf4j-log4j12 1.5.6 com.oracle ojdbc14 10.2.0.2.0
Keep in mind that the Oracle JDBC Driver has to be downloaded manually.
The public maven repos include only the Pom definition for the oracle driver. Generate with maven command line tool the eclipse project files:
mvn clean eclipse:clean eclipse:eclipse
The JDBC datasource is defined via Spring (applicationContext.xml):
Additionally we define the expected data as well in XML for DBUnit (expectedDataSet.xml):
Now we can code our JUnit 4.x Test to
- load data before the test method
- change the data via JDBC to emulate a application
- compare the changed data with expected data
- clean up the database
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:applicationContext.xml"})
public class TestDBUnitWithSpring {
@Autowired
private DataSource dataSource;
@Before
public void init() throws Exception{
// insert data into db
DatabaseOperation.CLEAN_INSERT.execute(getConnection(), getDataSet());
}
@After
public void after() throws Exception{
// insert data into db
DatabaseOperation.DELETE_ALL.execute(getConnection(), getDataSet());
}
private IDatabaseConnection getConnection() throws Exception{
// get connection
Connection con = dataSource.getConnection();
DatabaseMetaData databaseMetaData = con.getMetaData();
// oracle schema name is the user name
IDatabaseConnection connection = new DatabaseConnection(con,databaseMetaData.getUserName().toUpperCase());
DatabaseConfig config = connection.getConfig();
// oracle 10g
config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new Oracle10DataTypeFactory());
// receycle bin
config.setFeature(DatabaseConfig.FEATURE_SKIP_ORACLE_RECYCLEBIN_TABLES, Boolean.TRUE);
return connection;
}
private IDataSet getDataSet() throws Exception{
// get insert data
File file = new File("src/test/resources/dataset.xml");
return new FlatXmlDataSet(file);
}
@Test
public void testSQLUpdate() throws Exception{
Connection con = dataSource.getConnection();
Statement stmt = con.createStatement();
// get current data
ResultSet rst = stmt.executeQuery("select * from simple_data where id = 1");
if(rst.next()){
// from dataset.xml
assertEquals("value_before", rst.getString("content"));
rst.close();
// update via sql
int count = stmt.executeUpdate("update simple_data set content='value_after' where id=1");
stmt.close();
con.close();
// expect only one row to be updated
assertEquals("one row should be updated", 1, count);
// Fetch database data after executing the code
QueryDataSet databaseSet = new QueryDataSet(getConnection());
// filter data
databaseSet.addTable("simple_data", "select * from simple_data where id = 1");
ITable actualTable = databaseSet.getTables()[0];
// Load expected data from an XML dataset
IDataSet expectedDataSet = new FlatXmlDataSet(new File("src/test/resources/expectedDataSet.xml"));
ITable expectedTable = expectedDataSet.getTable("simple_data");
// filter unnecessary columns of current data by xml definition
actualTable = DefaultColumnFilter.includedColumnsTable(actualTable, expectedTable.getTableMetaData().getColumns());
// Assert actual database table match expected table
assertEquals(1,expectedTable.getRowCount());
assertEquals(expectedTable.getRowCount(), actualTable.getRowCount());
assertEquals(expectedTable.getValue(0, "content"), actualTable.getValue(0, "content"));
} else {
fail("no rows");
rst.close();
stmt.close();
con.close();
}
}
}
´The Oracle OC4J is based on the Orion Application Server source and still has some problems from the origin. I tested to deploy a little Apache CXF Annotation based Webservice into OC4J 10.1.3.4.0 with Eclipse WTP. Add in the Servers view a new local server from type “Oracle OC4J Standalone Server 10.1.3.n” and add the Web Application to this new J2EE container. When i start the server i got:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.apache.cxf.wsdl.WSDLManager' defined in class path resource [META-INF/cxf/cxf.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.apache.cxf.wsdl11.WSDLManagerImpl]: Constructor threw exception; nested exception is java.lang.ClassCastException: oracle.xml.parser.v2.DTD cannot be cast to org.w3c.dom.Element Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.apache.cxf.wsdl11.WSDLManagerImpl]: Constructor threw exception; nested exception is java.lang.ClassCastException: oracle.xml.parser.v2.DTD cannot be cast to org.w3c.dom.Element Caused by: java.lang.ClassCastException: oracle.xml.parser.v2.DTD cannot be cast to org.w3c.dom.Element at java.util.XMLUtils.load(XMLUtils.java:61) at java.util.Properties.loadFromXML(Properties.java:852) at org.apache.cxf.common.util.PropertiesLoaderUtils.loadAllProperties(PropertiesLoaderUtils.java:71) at org.apache.cxf.wsdl11.WSDLManagerImpl.registerInitialExtensions(WSDLManagerImpl.java:226) at org.apache.cxf.wsdl11.WSDLManagerImpl.registerInitialExtensions(WSDLManagerImpl.java:221) at org.apache.cxf.wsdl11.WSDLManagerImpl.(WSDLManagerImpl.java:110)
XML Parsing is done in Java based applications by a JAXP compliant Parser. The first Parser in the classpath sequence of jars wins and is used by all java classes of a application. Default for OC4J is to provide the Oracle XML Parser, which is a bit old. The solution is to force OC4J to use my JAXP Parser instead of the container Default Parser defined in the shared libraries.
My CXF Web Project is maven based. First thing to do is to add a new maven dependency to xerces 2.9.1 as JAXP Parser to use for CXF.
apache-xerces xercesImpl 2.9.1 jar compile
So create with ‘mvn package’ a war file in the target directory.
I removed the CXF Application from the OC4J Container inside the servers view in eclipse and start the OC4J server. Now log in the admin web console with
http://localhost:8888/em/console/ias/oc4j/home
Go to Applications and click on the deploy button. Select on the first screen the WAR file as local archive location. Enter on the second screen a application name and change the context path to your needs. Click on the third screen on the link to change your class loading. Remove all imported shared libraries and click on the checkbox below for “Search first locally for classes”. Click ok to go back to the third screen and click on deploy to start progress. Now it will successfully start the Application and you can see e.g. all deployed webservices with
http://localhost:8888/cxf-sample/
Keep in mind to adopt the context path “cxf-sample” of the url to your needs.
GWT 1.5 (official version is 1.5.2) is now finally released and not longer a release candidate. GWT is very nice as AJAX toolkit for a java programmer. You code your application in pure Java and all the JavaScript stuff is done behind the scenes. Important is to understand the build process. The Java Source Code is translated by the GWT Compiler to JavaScript Code. This GWT Compiler understands Java 1.5 with limited API. Eclipse has it’s own built-in Java compiler corresponding to the compiler level of the Java Project. Usage of unsupported Java functions will only be shown by the GWT compiler. Eclipse can only limit the access by setting access rules on the used JRE. In the project preferences under Java Build Path -> Libraries is the JRE. Under this Tree element is the access rules item. In the edit dialog can e.g. the usage limited to java.lang.* by setting “java/lang/*” as accessible. All other classes will not be available and cause compile errors in eclipse.
GWT ships with command line tools to create a new eclipse project including batch files to run the GWT compiler and launch files to start the hosted mode of GWT. Hosted mode starts a embedded tomcat and special GWT browser. The refresh button of this browser recompile the Java Code to JavaScript. Changes in the Java Code will directly shown in the browser after refresh. No restart is required.
GWT has two main concepts for a GWT application. The module defines the main class for a application and the AsyncCallbacks the service layer for accessing server side logic. The module name must be defined for the applicationCreator gwt command line tool as a java package name like com.mypackage.myapp.Main. Inside the source folder of the created eclipse project is the xml file with the gwt project definition and a Java class extending EntryPoint. The EntryPoint onModuleLoad method creates the UI of our GWT module. In the GWT docs online you will find a nice gallery with available ui elements called widgets. Remember that all code inside this method will be translated into JavaScript code.
Accessing business logic requires to define a interface extending RemoteService and a @RemoteServiceRelativePath annotation containing the name of the Service. This service must be implemented by class extending RemoteServiceServlet and implementing your interface. Additionally is a interface needed called <yourInterfaceName>Asyn, which contains the same signatures with a added AsyncCallback callback parameter e.g.
void sayHello(String text, AsyncCallback<String> callback);final MyServiceAsync service = (MyServiceAsync) GWT.create(MyService.class); service.sayHello(textbox.getText(), new AsyncCallback<String>() { public void onFailure(Throwable caught) { Window.alert(caught.getMessage()); } public void onSuccess(String result) { Window.alert(result); } }); } });
So many steps has to be made by hand to code a GWT app in this way.
Cypal Studio is a open source eclipse plugin to extend web tools platform of eclipse with GWT. Just extract the install zip file to the plugins subfolder of eclipse 3.3. With Eclipse 3.4 (aka Ganymede) you have to use the dropins/<pluginname>/plugins folder. Cypal integrates as a facet for dynamic web projects. Best environment is a JRe 1.5, GWT 1.5 and a Tomcat 5.5 with this JRE as run time. Call the New Project wizard of Eclipse and choose Dynamic web project. Choose the Tomcat 5.5 as target run time, set web modules version to 2.4 and choose “Cypal Studio for GWT” as configuration. Change either the workspace or project JRE to 1.5. If not done before you must now define the GWT home folder. Give here the path to the extracted GWT 1.5.2 archive. Select under File->New->Other..->Cypal Studio->GWT Module. Give the Module a Java Package name and and a name. The EntryPoint class, the html and the gwt xml file will be created. Under Run->Run configurations you will find “GWT hosted mode application”. Click on the new button, select the Project and click on the run button. The application will be compiled by GWT and the internal browser of GWT started with your Module. Remote Services can be created with File->New->Other..->Cypal Studio->GWT Remote Service. Enter here a name and a uri. Advised is to use the same value for Name and service URI e.g. MyService. This creates a public interface, a async interface, a implementation and change your gwt xml file to include this service as a servlet. Remember to use gwt serializable objects as parameters and return value for your service methods.
Seems to be an easy step to upgrade my local vmware server to the current version. VMWare server 2 changed the administration tool to a web interface like the one from the GSX or ESX server. First step is to uninstall the old vmware server and reboot. The download took a bit longer then before. Nearly 600mb comparing to 150mb for a 1.0.7 server install package for windows. You can change the ports of the administration web interface during installation. I leave this settings to default but changed that the server will not automatically started during windows boot. In the next screen is the possibility to change the default folder of vmware for images. I changed this to my existing folder of vmware server 1.0.6. Like before you have after installation a shortcut to the vmware server in the quicklaunch and on the desktop.
Firefox was a really a pain in the ass as browser for the web interface of beta 1 of vmware server 2. The download page now mention for Beta 2:
Firefox 3 as a supported browser for the management interface.
The icon open https://<hostname>:8333/ui/ as default url. Firefox 3 complains that the ssl certificate is self signed. You must click the link at the bottom to “add the exception” and the “add exception” button. The upcoming dialog request to get the certificate and let you after this download “confirm the security exception”.
Now the login screens ask for the credentials. Good question. The old native admin tool simply ask to login locally without any credentials. During installation where no user created or asked to define. Vmware use the local user database of windows as authentication provider. So define a new local user with admin rights or use a existing one to login.
My main vm image is a ubuntu server 8.04 with just a text console. Vmware use own linux modules for fast networking, folder sharing,… So i tried to upgrade my existing vmware-tools. Just start the vm and click the link to “install vmware tools”. It connects the virtual cdrom to readonly device with the install packages. Enter “mount /dev/cdrom /mnt/cdrom” inside the vm to copy install package to the tmp folder. You have to copy the *.tar.gz install package because ubuntu doesn’t work with RPMs like OpenSuse. The extracted folder contains the vmware-tools-install.pl script. Starting the install as root with ./vmware-tools-instal.pl or sudo ./vmware-tools-install.pl produce a error. VMware tools recognise the old kernel modules and stop the installation. The error message prints the name of the modules like vmxnet. So use “modprobe -v vmxnet” to get the path to the *.ko file. Delete it with rm and do this for all mentioned modules. Delete afterwards the old vmware settings by calling “rm -rf /etc/vmware*”. Now you can call the vmware-tools-install script to install successfully the kernel modules. Reboot the vm to use the new modules. Now you can see in the web interface e.g. the ip of the running vm.
I switched recently on my home server from OpenSuse 10.3 to Ubuntu Hardy Heron 8.0.4. Main reason was the package management with zypper as backend. Each Distro use several Software Repositories with RPMs where you can search for new software to install on your machine. Normally between four to eight repo’s are configured independent which distro you use. OpenSuse become more and more a pain in my ass. Main reason was the more and more increasing time which yast needs to show me the available software packages. For a test drive is VMWare Server really nice. Just setup a new VM, install a distro inside and see if it fits your needs.
Under Ubuntu you must first decide if you want the desktop or server edition. On my notebook was the primary requirement to have a back end for application server like Archiva or Nexus. Both very comfortable maven proxies with a web frontend. So i decided to install the server edition. The server edition have no window manager and starts a linux just with a console login. So far so good. A little bit hidden is the possibility to change the default screen solution from 800×600 to a larger one. Scrolling log or config files is not that pretty under such conditions.
The solution is in the /etc/grub/menu.1st file. In the end of the file is a list of linux versions. Each runnable linux configuration has a title, root, kernel and initrd line. For a 1024×768 you can append to the kernel line
vga=0×317
according to this howto. Ubuntu has in the last weeks published a new service pack called 8.04.1. Normal updated are installed with a “apt-get update” followed by “apt-get upgrade” to install updates for installed packages. I saw messages about retained packages after the availibity of this new service pack. A “apt-get dist-upgrade” forces to install the retained packages including a new kernel. Remember the line with the kernel paramater in the grub menu file. The update updates this file as well. Grateful it notice my changes and ask me what to do. My first intention was to say ok overwrite my changes and i add that vga parameter as well. That works but it can be handled much smarter. Linux kernel updates can be happen more often.
The solution is to add the vga parameter to defoptions line instead of the kernel line. This line is normally uncommented with a leading # character. So add this line
defoptions=vga=0×317
This 0×317 is the hex definition. Also possible is to write vga=719 with decimal notation.