Creating New Solution
From OpenSim
Creating New Solution
This guide aims to describe in detail how new C# solutions can be created according to the OpenSimulator conventions and minimum dependencies.
The topics included are:
- Directory structure
- Minimum dependencies
- Prebuild for creating build and solutions files for Monodevelop, Visual Studio 2005/2008 and NAnt - Prebuild SourceForge Project
- Database Connectivity with NHibernate - NHibernate Home
- Automated Unit Tests with NUnit - NUnit Home
- Source Code Documentation with Doxygen - Doxygen Home
Directory Structure
All the solution files are located under the same root folder. Bin directory as build output directory. It also contain permanently non embedded content and configuration files as Prebuild + NAnt combination does not currently support copying those files from the project folders. Because of this bin directory can not be cleaned empty with clean command.
SolutionExample - The solution root folder. /.nant - Custom extentions to NAnt build which are not generated by Prebuild. /bin - Build output directory. /doc - Doxygen generated documentation. /ProjectX - Project folder. /Resources - Xml configuration files like hibernate mappings and database value objects. /ProjectY - Project folder. /ProjectZ - Project folder. /TestProject - Project folder for solution unit tests.
Minimum Dependencies
Minimum external library dependencies for creating an application with MySQL database and XMLRPC connectivity are the following:
<Reference name="System"/>
<Reference name="System.Xml"/>
<Reference name="System.Data"/>
<Reference name="NHibernate.dll" localCopy="true" />
<Reference name="NHibernate.Mapping.Attributes.dll" localCopy="true" />
<Reference name="log4net.dll" localCopy="true" />
<Reference name="nunit.framework.dll" localCopy="true" />
<Reference name="XMLRPC.dll" localCopy="true" />
<Reference name="Iesi.Collections.dll" localCopy="true" />
<Reference name="MySql.Data.dll" localCopy="true" />
<Reference name="System.Data.SQLite.dll" localCopy="true" />
Its best to use same versions the OpenSimulator trunk is using.
Prebuild
Prebuild.exe generates solution and project build files for Monodevelop, Visual Studio 2005/2008 and NAnt based on the prebuild.xml located in the solution root folder. Prebuild is run using runprebuild.sh (Linux), runprebuild.bat (Windows / Visual Studio 2005) or runprebuild2008.bat (Visual Studio 2008). These files can be copied from OpenSimulator trunk.
Example prebuild.xml:
<?xml version="1.0" encoding="utf-8" ?>
<Prebuild xmlns="http://dnpb.sourceforge.net/schemas/prebuild-1.7.xsd" version="1.7">
<Solution name="OpenSim.Example" activeConfig="Debug" path="./" version="0.0.1-$Rev: 0001 $">
<Configuration name="Debug">
<Options>
<CompilerDefines>TRACE;DEBUG</CompilerDefines>
<OptimizeCode>false</OptimizeCode>
<CheckUnderflowOverflow>false</CheckUnderflowOverflow>
<AllowUnsafe>false</AllowUnsafe>
<WarningLevel>4</WarningLevel>
<WarningsAsErrors>false</WarningsAsErrors>
<SuppressWarnings></SuppressWarnings>
<OutputPath>bin</OutputPath>
<DebugInformation>true</DebugInformation>
<IncrementalBuild>true</IncrementalBuild>
<NoStdLib>false</NoStdLib>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<CompilerDefines>TRACE</CompilerDefines>
<OptimizeCode>true</OptimizeCode>
<CheckUnderflowOverflow>false</CheckUnderflowOverflow>
<AllowUnsafe>false</AllowUnsafe>
<WarningLevel>4</WarningLevel>
<WarningsAsErrors>false</WarningsAsErrors>
<SuppressWarnings></SuppressWarnings>
<OutputPath>bin</OutputPath>
<DebugInformation>false</DebugInformation>
<IncrementalBuild>true</IncrementalBuild>
<NoStdLib>false</NoStdLib>
</Options>
</Configuration>
<Project name="Example.Library" path="ExampleLibrary" type="Library">
<Configuration name="Debug">
<Options>
<OutputPath>../lib</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../lib</OutputPath>
</Options>
</Configuration>
<ReferencePath>../lib</ReferencePath>
<ReferencePath>../lib</ReferencePath>
<Reference name="System"/>
<Reference name="System.Xml"/>
<Reference name="System.Data"/>
<Reference name="System.Drawing"/>
<Reference name="NHibernate.dll" localCopy="true" />
<Reference name="NHibernate.Mapping.Attributes.dll" localCopy="true" />
<Reference name="log4net.dll" localCopy="true" />
<Reference name="nunit.framework.dll" localCopy="true" />
<Reference name="XMLRPC.dll" localCopy="true" />
<Reference name="Iesi.Collections.dll" localCopy="true" />
<Reference name="MySql.Data.dll" localCopy="true" />
<Reference name="System.Data.SQLite.dll" localCopy="true" />
<Files>
<Match pattern="*.cs" recurse="true"/>
<Match path="Resources" pattern="*.xml" buildAction="EmbeddedResource"/>
<Match pattern="*.config" buildAction="Content" copyToOutput="Always" />
</Files>
</Project>
<Project name="Example.Console" path="ExampleConsole" type="Exe">
<Configuration name="Debug">
<Options>
<OutputPath>../bin</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../bin</OutputPath>
</Options>
</Configuration>
<ReferencePath>../lib</ReferencePath>
<Reference name="System"/>
<Reference name="System.Xml"/>
<Reference name="System.Data"/>
<Reference name="System.Drawing"/>
<Reference name="NHibernate.dll" localCopy="true" />
<Reference name="NHibernate.Mapping.Attributes.dll" localCopy="true" />
<Reference name="log4net.dll" localCopy="true" />
<Reference name="nunit.framework.dll" localCopy="true" />
<Reference name="XMLRPC.dll" localCopy="true" />
<Reference name="Iesi.Collections.dll" localCopy="true" />
<Reference name="MySql.Data.dll" localCopy="true" />
<Reference name="System.Data.SQLite.dll" localCopy="true" />
<Reference name="Example.Library" localCopy="true"/>
<Files>
<Match pattern="*.cs" recurse="true"/>
</Files>
</Project>
</Solution>
</Prebuild>
Database Connectivity with NHibernate
NHibernate can be configured programmatically, using nhibernate.xml or .config files. OpenSimulator project uses Nini to load database configuration form ini-files and applies them programmatically to NHibernate configuration.
Database Unit Test Configuration
To leverage ADO.NET connection pooling in unit tests against SQLite or MySQL you can use the following configuration for the test dll:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
</configSections>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.SQLite20Driver</property>
<property name="connection.connection_string">
Data Source=OpenSimExample.db;Version=3
</property>
<property name="dialect">NHibernate.Dialect.SQLiteDialect</property>
<property name="query.substitutions">true=1;false=0</property>
<property name="show_sql">true</property>
</session-factory>
<!--
<session-factory>
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider, NHibernate
</property>
<property name="connection.connection_string">
Server=server;Database=database;User ID=user;Password=password
</property>
<property name="dialect">NHibernate.Dialect.MySQL5Dialect</property>
</session-factory>
-->
</hibernate-configuration>
</configuration>
Database Naming Convention
- Table naming convetion: word_word
- Column naming convetion: WordWord
Mapping
Mapping of C# value objects and database tables can be done using the following ObjectName.hbm.xml files located in Resources:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Example.Library.Resources.TestObject, Example.Library" table="test_object" lazy="false">
<id name="TestId" column="TestId" type="Guid">
<generator class="assigned" />
</id>
<property name="Name" type="String" length="45" />
</class>
</hibernate-mapping>
The mapped value object:
using System;
using System.Collections.Generic;
using System.Text;
namespace Example.Library.Resources
{
/// <summary>
/// Object for database tests.
/// </summary>
public class TestObject
{
private Guid testId=Guid.Empty;
public Guid TestId {
get
{
return testId;
}
set
{
testId = value;
}
}
private String name;
public String Name {
get
{
return name;
}
set
{
name = value;
}
}
}
}
Database Unit Test
Example unit test using nhibernate connection:
using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using NHibernate;
using NHibernate.Cfg;
using System.IO;
using NHibernate.Tool.hbm2ddl;
namespace Example.Library.Resources
{
[TestFixture]
public class DatabaseTest
{
[Test]
public void TestDatabase()
{
Configuration configuration = new Configuration();
configuration.AddAssembly(this.GetType().Assembly);
if (!File.Exists("OpenSimExample.db"))
{
SchemaExport schemaExport = new SchemaExport(configuration);
schemaExport.Create(true, true);
}
ISessionFactory sessions = configuration.BuildSessionFactory();
using (ISession session = sessions.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
TestObject newObject = new TestObject();
newObject.TestId = Guid.NewGuid();
newObject.Name = "test-name";
session.Save(newObject);
TestObject loadedObject=(TestObject)session.Load(typeof(TestObject),newObject.TestId);
Assert.AreEqual(newObject.Name,loadedObject.Name);
session.Delete(loadedObject);
transaction.Commit();
}
}
}
}
}
Automated Unit Tests
Unit tests are written using NUnit. You can add NUnit to build by adding the following build target to the .nant/local.include file:
<target name="test" description="Runts automated unit tests." depends="build-release">
<copy todir="lib">
<fileset basedir="./TestProjec" >
<include name="*.config" />
</fileset>
</copy>
<nunit2>
<formatter type="Plain" />
<test assemblyname="lib/TestProject.dll" appconfig="lib/TestProject.dll.config" />
</nunit2>
</target>
Running the above test with nant will result the following console output:
test:
[copy] Copying 1 file to 'C:\Development\OpenSimExample\lib'.
[nunit2] drop table if exists test_object
[nunit2] create table test_object (
[nunit2] TestId UNIQUEIDENTIFIER not null,
[nunit2] Name TEXT,
[nunit2] primary key (TestId)
[nunit2] )
[nunit2] NHibernate: INSERT INTO test_object (Name, TestId) VALUES (@p0, @p1); @p0 = 'test-name', @p1 = '3aa93503-3cc4-4241-862a-c8ab3fb6ac0d'
[nunit2] NHibernate: DELETE FROM test_object WHERE TestId = @p0; @p0 = '3aa93503-3cc4-4241-862a-c8ab3fb6ac0d'
[nunit2]
[nunit2] Tests run: 1, Failures: 0, Not run: 0, Time: 2.211 seconds
[nunit2]
[nunit2]
[nunit2]
Source Code Documentation with Doxygen
You can copy doc/doxygen.conf from OpenSimulator trunk to your solution and configure it appropriately.