db4o Developer Community

db4o open source object database, native to Java and .NET
Welcome to db4o Developer Community Sign in | Join
in Search
More Search Options

Product News from the Core Team

This blog features product news right from the core developer team, once new features and functions get checked into Subversion, available as Continuous Build every 2 hours.

  • Performance Contest - for one more month

    Do you like profiling? Do you like tuning code? If you do, how about taking part in the db4o performance contest? We offer USD 6000 in prizes for the best contributions to make db4o faster.

    We have made it very easy for you to get started by providing an Eclipse workspace set up with the db4o sources and the Poleposition benchmark.

    Links to get you started:
    Performance Contest page
    "Getting Started" video
    Performance Contest Forum

    The contest has been running for a month already and we are seeing first contributions coming in.

    Andrew has improved sorted queries and provides a UTF-8 string encoder.
    Erik is working on a query cache to make queries reusable.

    Can you beat their patches? I am sure you can.
    The contest is still open for contributions for one more month until August 15.

  • Implications of instrumenting assemblies for Transparent Activation / Persistence in db4o - Part I

    As the popular saying  tell us, there's no such thing as free lunch. It is no different for work related subjects.

    When we introduced Transparent Activation (TA) concept we knew that it could make developer's life easier (by presenting a simpler model for object life cycle): developers would not be required to think about activation depths again; just let db4o activate your objects when it's need.

    IMHO, it was a great improvement since it not only simplifies developer's life as well brings some performance gains also (once objects get activated only when needed there's no wasted time activating objects not needed). But this was not without coasts: to benefit from this simpler model, developers were required to implement IActivatable interface for each object that they wanted to be TA. Also, once enabled, any non TA aware object will be fully activated at retrieval time.

    Time passed and we introduced  a way relieve developers from the need to implement Activatable interface, i.e, to make classes TA aware with no effort from developers. This is accomplished through a technique called instrumentation in which we dive into byte code level doing something like:

    1. Find each type declared in a specific assembly (.net) / jar or class (java)
    2. Analise each type found in step 1 to check whether it is a potential candidate for TA or not
    3. If we found a potential candidate for TA
      • Make the type to implement IActivatable interface
      • Implement IActivatable methods
      • Ensure that the object will be activated prior to any field access by inspecting each field access in this type and inserting the required Activate() / activate() call prior to it.
    4. Save the binary component

    A pretty straight approach, I'd say.

    But even when using instrumentation there are some implications that developers should be aware of. To illustrate, think about assembly signing; this is a process in which a developer "seals" an assembly contents by digitally signing it (the whole concept is beyond this post).

    Basically, by signing an assembly a developer is providing ways to administrators to selectively grant access to assemblies based on the private key (related to the public key) used to sign it; also, signed assemblies are tamper resistant which means that changes (in byte code level) don't go unnoticed.

    By the above description it's clear that instrumenting  a signed assembly turns it invalid afterward (since its contents gets changed) and any tentative of loading it will fail with a invalid signature error.

    So, after instrumenting signed assemblies you will need to sign them again but, IMHO, you should never, ever, instrument assemblies that are not under your control, so I'd suggest you to just change your build scripts so instrumentation takes place prior to signing.

    To help developers detect this, starting from version 7.4.52 Db4oTool will emit an warning when asked to instrument (whether for TA/TP or Native Queries optimizations) a signed/delay signed assembly.

    Just for the sake of completeness I've included the following walk through on how to create assemblies that are instrumented and signed (for a in depth discussion on signing assemblies please, read this).

    VS Project Properties VS Project Properties 2
    1. In Visual Studio, open project properties window and select signing tab.

    2. Select Sign the assembly;

    3. Expand Choose a strong name key file drop down listbox and either, select a previously created key or create a new one by selecting <New...> option;

    4. Select Delay sign only checkbox;

    5. Save your project and build

    6. Instrument your assembly (either running Db4oTool or through Db4oToolEnhancerMSBuildTask)

    7. After instrumentation, run sn tool as follows to finish the sign process:

      sn -Ra myassembly.dll mykey.snk
    That's it! Your assembly is instrumented and signed.

    In the next post I'll address some other implications / pitfalls regarding instrumentation for TA/TP.

    Thoughts?

  • db4o-7.4 Development Release

    The following Jira tasks and bugs were resolved for db4o-7.4 development release:

    • DRS-98 - NullPointerException in replicate method
    • DRS-97 - Ensure dRS.NET can gracefully handle delegates in untyped fields and arrays
    • DRS-95 - dRS.NET fails with arrays/untyped fields
    • DRS-94 - Replication fails if the java platform doesn't support serializable constructor and the objects to be replicated don't have default constructors
    • DRS-93 - Replication fails for arrays in untyped fields
    • COR-1297 - Spike: Class derived from ArrayList using custom Typehandler
    • COR-1295 - Convert ListTypeHandlerTestSuite to .NET
    • COR-1291 - Backport "[Linq] Enum comparisons are not optimized" to 7.2
    • COR-1289 - Clean up db4obuild for opening to the public
    • COR-1284 - Defragment against unknown classes runs into NPE on btree index lookup
    • COR-1283 - Update old multidimensional arrays to null bitmap handling
    • COR-1282 - [decaf] functional test for resolving db4oj/db4ojdk1.2 conversion issues
    • COR-1281 - Running out of disk space causes unrecoverable data corruption
    • COR-1279 - Delegate in untyped arrays cause ObjectNotStorableException
    • COR-1276 - prepare Jprobe paircast and blog
    • COR-1275 - Db4o should not wrap exceptions thrown during event handling
    • COR-1265 - ArrayHandler: Defragment old databases
    • COR-1264 - ArrayHandler: Updating from old databases to new format
    • COR-1263 - ArrayHandler: Bitmap Marshalling Format
    • COR-1262 - Pass configuration on to reflector on startup
    • COR-1261 - Move constructor handling into reflector
    • COR-1255 - Provide Feedback on latest OMG SBQL vs, LINQ comparison
    • COR-1254 - _blob.ReadFrom() throws Object reference not set to an instance of an object. in C/S mode
    • COR-1247 - Create releae notes for production release 7.2
    • COR-1246 - Create release notes for 6.4 stable release
    • COR-1227 - Prepare 7.2 "Production" release (freeze trunk)
    • COR-1216 - TracerBullet: Deletion for Java ArrayList using the new Typehandler
    • COR-1214 - Db server closed when upgraded from 5.5 version to 6.4.14.8331 with btree based freespace management system
    • COR-1153 - [Linq] Enum comparisons are not optimized
    • COR-1129 - TracerBullet: Special use cases for Java ArrayList using the new Typehandler
    • COR-897 - Concurrency tests for close/timout scenarios
  • flushFileBuffers(false) and the C in ACID

    The short story:
    Configuration.flushFileBuffers(false) is no more. If you still want to configure the behaviour that used to be available in db4o 6.1, you can do so by setting up IoAdapters as follows:

    RandomAccessFileAdapter randomAccessFileAdapter = new RandomAccessFileAdapter();
    NonFlushingIoAdapter nonFlushingIoAdapter = 
                                     new NonFlushingIoAdapter(randomAccessFileAdapter);
    CachedIoAdapter cachedIoAdapter = new CachedIoAdapter(nonFlushingIoAdapter);
    Configuration configuration = Db4o.newConfiguration();
    configuration.io(cachedIoAdapter);
    Db4o.openFile(configuration, PATH);
    

    The long story:
    We do a lot of things for consistent transactions (for the C in ACID). A commit of a db4o transaction consists of 4 write phases:

    • Writing a commit log to the database file
    • Switching the database file to commit mode
    • Committing all slots
    • Switching the database file to normal mode 

    Because a cache at any level may turn around the write order of individual slots and because a failure may end up in a partial write, it is essential that all data is flushed to the device after each one of these 4 phases.

    This flush call takes a lot of time. It is the slowest part of the commit. On a system where you are sure enough (100% ? ) that the commit process always is successful, a tuning switch that skips flushing sounds like a smart way to improve performance.

    That's what we thought and why we added the #flushFileBuffers(false) configuration switch in the first place.

    Starting with db4o 6.4 we have added a new CachedIoAdapter to the IO layer as the default. This IoAdapter uses the #sync() calls as a signal to flush it's pages to the database file. What we did not think about well enough when we added this functionality: If users use the #flushFileBuffers(false) tuning switch, they also skip the flush of the CachedIoAdapter.

    This issue does not surface as long as the database file is always shut down correctly, so it took us a long time to realize how serious it can be. Since we have switched db4o 6.4 to "stable", there have been a couple of support discussions like this one:

    User: "We have switched to db4o 6.4. We are sometimes getting new exceptions like IncompatibleFileException."
    db4objects: "Uhoh. Are you maybe using #flushFileBuffers(false) in productive use? Please don't do that. Don't tell us that you are."
    User: "Yes we are."

    After investing some time and thought we have figured that the CachedIoAdapter makes it much much more likely that corruption can happen if a database file is not shut down correctly (with the #flushFileBuffers(false) configuration call). Because this is so serious (it leads to corrupted database files), we have decided to turn off this configuration switch completely.

    A similar functionality as in 6.1 is still available, if you really know what you are doing and if you know that you are taking the risc of corrupted database files if your system is halted because someone hits the power-off switch by accident in the middle of a commit. With the layer of IoAdapters, as outlined at the beginning of this posting, the risk of corruption is fairly small, just as it used to be in 6.1. Corruption will only happen if the OS cache or disc cache changes around the order of writes.

    The changes are effective and the new IoAdapter is available from iteration 48 and revision 10977 onwards, e.g. from db4o versions:
    6.4.48.10977
    7.2.48.10977
    7.4.48.10977

    For previous stable 6.4 versions we strongly recommend not to use the #flushFileBuffers(false) setting in production use.

    Many thanks to our users for reporting their problems!

  • Committed callbacks, pushed updates and read committed isolation revisited

    Some time ago we presented Pushed Updates as a sample application for Committed Callbacks in this blog. Recently we put a similar mechanism in a slightly different context. Since we encountered some perceived ambiguity concerning db4o transaction semantics, and since we were in for a little surprise ourselves, I'd like to briefly rehash this topic.

    Pushed Updates basically are a mechanism to provide READ COMMITTED isolation from the point of view of your application. Wait - doesn't db4o provide that out of the box?!? Well, it does. Any query is guaranteed to return objects in their most recently committed state - unless they are still in memory on the requesting client, that is. db4o cannot change the state of of a live object that may be involved in application level processes at the same time. Only the application can judge whether it is safe to modify a given object, and Committed Callbacks are the way to transfer this responsibility.

    Note that "in memory" above does not mean "in use by the application", and not even necessarily "referenced by the application". An object may still survive in the reference system some time after it has been discarded by the application, until the GC eventually hits. There is no remotely performant way to check whether there exist hard references to a given object.

    So much for the theory, let's look at the code. The core of the Pushed Updates example looked like this:
    private EventListener4 createCommittedEventListener(final ObjectContainer objectContainer){
      return new EventListener4() {
        public void onEvent(Event4 e, EventArgs args) {
          ObjectInfoCollection updated = ((CommitEventArgs)args).updated();
          Iterator4 infos = updated.iterator();
          while(infos.moveNext()){
            ObjectInfo info = (ObjectInfo) infos.current();
            Object obj = info.getObject();
            objectContainer.ext().refresh(obj, 2);
          }
        }
      };
    }
    EventListener4 committedEventListener = createCommittedEventListener(client);
    EventRegistry eventRegistry = EventRegistryFactory.forObjectContainer(client);
    eventRegistry.committed().addListener(committedEventListener);
    This code registers a callback for committed events. When invoked, it will traverse all the objects that have been updated during this commit and refresh them. (The magic depth of two is a reverence to collections, forcing them to refresh their elements, too.)

    Now this works nicely - in networking C/S mode, where the communication layer between client and server takes care of the correct "translation" of object identities. In embedded C/S mode, however, there is no translation - clients run in the same "live object space" as the server, the only thing they don't share is the weak reference system that defines their notion of object identities. And so the ObjectInfo will contain the server's instance of this persisted object, while the client will have its own version that it won't be able to map to the "stranger".

    The fix is easy (and works for networking C/S, too, of course): We have to take care of the translation ourselves via ID lookup. In code:
    public void onEvent(Event4 e, EventArgs args) {
      Transaction trans = ((InternalObjectContainer)client).transaction();
      ObjectInfoCollection updated = ((CommitEventArgs)args).updated();
      Iterator4 infos = updated.iterator();
      while(infos.moveNext()){
        ObjectInfo info = (ObjectInfo) infos.current();
        Object obj = trans.objectForIdFromCache((int)info.getInternalID());
        if(obj == null) {
          continue;
        }

        client.refresh(obj, 2);
      }
    }
    Here we have to fall back on the InternalObjectContainer interface. Don't be too scared of this - it's not really under the hood stuff, but it's indeed intended to be used for 3rd party implementations of pluggable db4o features intended to be run inside the core, like type handlers, reflectors - and callbacks. Note that this variant also keeps the handler from further processing of objects that haven't been known to this client, anyway.

    Bottom line: Transaction semantics and live in-memory objects are not entirely trivial to align, object identities can be tricky, and this is the recommended generic way for doing Pushed Updates. For networking C/S, the original Pushed Updates example is fine as it was.
  • Sharpen your Java app now: Java to C# converter released as free software

    As of today, db4objects releases its Eclipse based Java to C# source code conversion tool "sharpen" as free software.

    sharpen is the "secret sauce" that enables us to provide the [db4o object database engine] in native versions for the Java and .NET platforms from a single code base.

    Features include:
    • mapping between Java and .NET native type systems
    • compliance with C# coding conventions
    • user defined namespace/class/method mappings
    • method to property mappings
    • Generics support
    • partial conversions
    • mixing native and converted C# sources
    • VS solution file support
    • Ant integration
    sharpen is used extensively in the db4o build system, generating most of the db4o engine core code and the unit test suites from the Java sources.

    Before you start dreaming: sharpen is not a "magic wand". Don't expect to feed it an arbitrary Java app and receive a running .NET version at the push of a button. The translation process will require some design compromises on the Java side, and parts of the .NET code still have to be hand crafted and integrated into the converted sources. Still, we believe sharpen provides an amazingly smooth way to bridge the gap between Java and .NET and create real cross platform applications.

    We are looking forward to see which sharpen propelled applications will cross the language chasm, and we're hoping on your feedback and your contributions that will help to cover automatic conversion of even more Java constructs and idioms, moving Java/.NET cross platform integration to a new level.

    sharpen is released under the GPL. The svn repository, documentation and issue tracker are online. All that's missing now is you bringing your Java app to the .NET platform. To get you started, here is the full anatomy of a simplistic application developed with sharpen. Have fun!
  • Smart java to c# conversion for the masses with sharpen

    As of Today our so far internal java to c# conversion utility, sharpen, is being released as free software.

    As an example of its usage we're going to write a simple contact management application in java and convert it to c#.

    While it is possible to use sharpen to convert a complete application it is advisable to handle this as an iterative process: java a little, sharpen a little. The reason for this is that not all java constructs and idioms can be handled out of the box by sharpen, thus the translation might influence the design of the original java code.

    As a first step we'll come up with a minimum skeleton for our console application, ignoring any "business logic" for now:

    package contacts;

    public class Program {

    public static void main(String[] args) {
    boolean running = true;
    while (running) {
    String option = Console.prompt("(a)dd new entry, (l)ist entries, (q)uit");
    if (option.isEmpty()) continue;
    switch (option.charAt(0)) {
    case 'q':
    running = false;
    break;
    default:
    System.out.println("'" + option + "' DOES NOT COMPUTE!");
    }
    }
    }
    }
    package contacts;

    import java.io.*;

    public class Console {

    public static String prompt(String prompt) {
    System.out.println(prompt);
    return readLine();
    }

    private static String readLine() {
    try {
    return new BufferedReader(new InputStreamReader(System.in)).readLine();
    } catch (IOException e) {
    throw new RuntimeException(e);
    }
    }
    }

    Here we can already see the first design decision triggered by sharpen. The console APIs for java and .net are quite different and although sharpen can handle IO primitives gracefully, it doesn't support translating our specific use of "System.in". The obvious way of handling situations like this is to factor out the required functionality into a specialized class and provide dedicated implementations for java and .net.

    With the first java iteration complete let's get to sharpening it.

    Before we can get any conversion done, the sharpen.core plugin must be installed. From inside eclipse:

    • Checkout sharpen.core from db4o's subversion repository at https://source.db4o.com/db4o/trunk/sharpen/
    • Right click the freshly checked out project in the "Package Explorer" and choose "Export" from the context menu;
    • Expand the "Plug-in Development" folder and select "Deployable plug-ins and fragments";
    • Set "Destination" to the root folder of your eclipse installation and click "Finish";

    We're ready to automate the conversion from java to c# with an ant script. In order to make this task easier, we will reuse a few sharpen related macros defined in sharpen-common.xml.

    <project name="ContactList" default="build-dotnet">

    <import file="build-properties.xml" />
    <import file="sharpen-common.xml" />

    <target name="build-dotnet" depends="sharpen">
    <exec executable="${nant.exe}">
    </exec>
    </target>

    <target name="sharpen" depends="init">

    <prepare-sharpen-workspace project="ContactList" dir="${sharpen.workspace.dir}" />

    <sharpen workspace="${sharpen.workspace.dir}" resource="ContactList/src">
    </sharpen>

    </target>

    <target name="init">

    <reset-dir dir="${sharpen.workspace.dir}" />

    </target>

    </project>

    Here we are using the common strategy of externalizing environment specific properties to a dedicated file (build-properties.xml):

    <project name="build properties">
    <property name="sharpen.workspace.dir" value="build" />
    <property name="eclipse.home" value="c:/java/eclipse" />
    <property name="nant.exe" value="c:/dotnet/nant-0.85/bin/NAnt.exe" />
    </project>

    We're not using a plain java properties file because the nant script which is used for compiling the converted sources also needs some of these definitions:

    <?xml version="1.0"?>
    <project name="ContactList" default="build">

    <include buildfile="build-properties.xml" />

    <property name="src.dir" value="${sharpen.workspace.dir}/ContactList.net" />
    <property name="bin.dir" value="${src.dir}/bin" />

    <target name="build">
    <csc target="exe" output="${bin.dir}/ContactList.exe">
    <sources basedir="${src.dir}">
    <include name="**/*.cs" />
    </sources>
    </csc>
    </target>

    </project>

    Running ant we get good news and bad news. The good news are sharpening went fine:

    sharpen:
    [mkdir] Created dir: build\ContactList
    [copy] Copying 2 files to build\ContactList
    [echo] org.eclipse.core.launcher.Main -data build -application sharpen.core.application ContactList/src
    [java] project: ContactList
    [java] source folder: src
    [java] Pascal case mode: None
    [java] Console.java
    [java] Program.java
    [java] Conversion finished in 3110ms.

    C# compilation didn't go so well:

    [exec] [csc] Compiling 2 files to 'ContactList.net\bin\ContactList.exe'.
    [exec] [csc] ContactList.net\src\contacts\Console.cs(15,16): error CS0246: The type or namespace name 'java' could not be found (are you missing a using directive or an assembly reference?)

    ...

    [exec] [csc] ContactList.net\src\contacts\Program.cs(12,16): error CS0117: 'string' does not contain a definition for 'isEmpty'

    Before we fix those errors let's take a look at how Program.java got translated to c#:

    namespace contacts
    {
    public class Program
    {
    public static void Main(string[] args)
    {
    bool running = true;
    while (running)
    {
    string option = contacts.Console.prompt("(a)dd new entry, (l)ist entries, (q)uit"
    );
    if (option.isEmpty())
    {
    continue;
    }
    switch (option[0])
    {
    case 'q':
    {
    running = false;
    break;
    }

    default:
    {
    System.Console.Out.WriteLine("'" + option + "' DOES NOT COMPUTE!");
    break;
    }
    }
    }
    }
    }
    }

    It looks good except for javaisms like the lower case namespace and method names which can be fixed with the introduction of the "pascalCase+" sharpen command line option.

    To get rid of the c# compilation errors we must provide a platform specific version of the Console class and tell sharpen to ignore its java counterpart using the @sharpen.ignore javadoc annotation.

    /**
    * @sharpen.ignore
    */
    public class Console {

    ...

    As a very useful convention we like to keep native and converted c# sources separate from each other by introducing a subfolder named "native".

    Here's our native c# Console implementation:

    namespace Contacts
    {
    public static class Console
    {
    public static string Prompt(string message)
    {
    System.Console.WriteLine(message);
    return System.Console.ReadLine();
    }
    }
    }

    The remaining compiler error is caused by calling the String.isEmpty which has no equivalent on the .net side. We'll sneak around this issue for the time being by rewriting the java side condition in terms of String.length:

                if (option.length() == 0) continue;

    Our build runs green now and the .net application is functional. We're ready to move on to the business logic.

    We'll start with a collection based implementation to be enhanced with persistence later in the process.

    package contacts;

    public class Contact {

    private String _name;
    private String _email;

    public Contact(String name, String email) {
    _name = name;
    _email = email;
    }

    public String name() {
    return _name;
    }

    public String email() {
    return _email;
    }
    }
    package contacts;

    import java.util.*;

    public class ContactList {

    private List<Contact> _entries = new ArrayList<Contact>();

    public void add(Contact contact) {
    _entries.add(contact);
    }

    public Iterable<Contact> entries() {
    return _entries;
    }
    }
    package contacts;

    public class Program {

    private ContactList _contacts = new ContactList();

    public void readEvalLoop() {
    boolean running = true;
    while (running) {
    String option = prompt("(a)dd new entry, (l)ist entries, (q)uit: ");
    if (option.length() == 0) continue;
    switch (option.charAt(0)) {
    case 'a':
    addEntry();
    break;

    case 'l':
    listEntries();
    break;

    case 'q':
    running = false;
    break;
    default:
    System.out.println("'" + option + "' DOES NOT COMPUTE!");
    }
    }
    }

    private String prompt(String message) {
    return Console.prompt(message);
    }

    private void listEntries() {
    for (Contact c : _contacts.entries()) {
    System.out.println(c.name() + " <" + c.email() + ">");
    }
    }

    private void addEntry() {
    String name = prompt("Name: ");
    String email = prompt("Email: ");
    _contacts.add(new Contact(name, email));
    }

    public static void main(String[] args) {
    new Program().readEvalLoop();
    }
    }

    A quick look at the converted object model shows that although correct the code still looks a bit alien to .net:

    namespace Contacts
    {
    public class Contact
    {
    private string _name;

    private string _email;

    public Contact(string name, string email)
    {
    _name = name;
    _email = email;
    }

    public virtual string Name()
    {
    return _name;
    }

    public virtual string Email()
    {
    return _email;
    }
    }
    }
    namespace Contacts
    {
    public class ContactList
    {
    private System.Collections.Generic.IList<Contacts.Contact> _entries = new System.Collections.Generic.List
    <Contacts.Contact>();

    public virtual void Add(Contacts.Contact contact)
    {
    _entries.Add(contact);
    }

    public virtual System.Collections.Generic.IEnumerable<Contacts.Contact> Entries()
    {
    return _entries;
    }
    }
    }

    Contact.Name, Contact.Email and ContactList.Entries would look better as properties and the qualified names used everywhere look rather untidy.

    We can solve the first issue using the @sharpen.property javadoc annotation:

        /**
    * @sharpen.property
    */
    public Iterable<Contact> entries() {
    return _entries;
    }
    Proper "using" directives can be enforced with the "-organizeUsings" command line option:
            <sharpen workspace="${sharpen.workspace.dir}" resource="ContactList/src">
    <args>
    <arg value="-pascalCase+" />
    <arg value="-organizeUsings" />
    </args>
    </sharpen>
    The c# version of ContactList is now indistinguishable from hand crafted code:
    using System.Collections.Generic;
    using Contacts;

    namespace Contacts
    {
    public class ContactList
    {
    private IList<Contact> _entries = new List<Contact>();

    public virtual void Add(Contact contact)
    {
    _entries.Add(contact);
    }

    public virtual IEnumerable<Contact> Entries
    {
    get
    {
    return _entries;
    }
    }
    }
    }

    We now have a complete cross platform contact management application. The only feature missing for the huge marketing success it deserves is persistence which can be easily implemented with db4o.

    We downloaded the db4o production packages for both java and .net 2.0 from here and added the corresponding paths to our build-properties.xml file:

        <property name="db4o.jar" value="c:/java/db4o-7.2/lib/db4o-7.2.39.10644-java5.jar"  />
    <property name="db4o.dll" value="c:/dotnet/db4o-7.2/bin/net-2.0/Db4objects.Db4o.dll" />
    <property name="eclipse.home" value="c:/java/eclipse" />

    All we have to do now is to change ContactList to use a db4o ObjectContainer instead of an ArrayList as its storage backend:

    package contacts;

    import com.db4o.*;

    public class ContactList {

    private ObjectContainer _container = Db4o.openFile("contacts.db4o");

    public void add(Contact contact) {
    _container.store(contact);
    }

    /**
    * @sharpen.property
    */
    public Iterable<Contact> entries() {
    return _container.query(Contact.class);
    }

    public void close() {
    _container.close();
    }
    }

    We also have to make sure that the ObjectContainer is shutdown cleanly on application exit, for that purpose we introduced the ContactList.close method above which must be called from the main application class:

        public static void main(String[] args) {
    Program program = new Program();
    try {
    program.readEvalLoop();
    } finally {
    program.close();
    }
    }
    Getting the c# version to work requires additional configuration switches for the sharpen task. First the java code now depends on the db4o jar which must be known at translation time. Second, the .net db4o interface operates against the native .net type system (this is a great candidate for a default setting) and uses namespace and interface names more inline with the .net design guidelines:
            <sharpen workspace="${sharpen.workspace.dir}" resource="ContactList/src">
    <args>
    <arg value="-pascalCase+" />
    <arg value="-organizeUsings" />

    <arg value="-cp" />
    <arg file="${db4o.jar}" />

    <arg value="-nativeTypeSystem" />
    <arg value="-nativeInterfaces" />

    <arg value="-typeMapping" />
    <arg value="com.db4o.Db4o" />
    <arg value="Db4objects.Db4o.Db4oFactory" />

    <arg value="-namespaceMapping" />
    <arg value="com.db4o" />
    <arg value="Db4objects.Db4o" />
    </args>
    </sharpen>

    Here's an screenshot of both versions of the application running side by side:

    Attachment: sharpen.demo.gif (36912 bytes)

    This was a minimalist example of converting a java application to c# using the open source sharpen tool. Our intention was to show how sharpen can be used in a realistic setting requiring some manual intervention of the developer during all phases of the process. For a more complex cross-platform project based on sharpen take a look at the db4o source code repository :).

    The complete source code for this application together with build scripts can be found here.

    Sharpen documentation can be found here.

    The issue tracker is here.

    We are looking forward to see which projects will make use of sharpen in the future now that it is out in the wild.

  • 6.4 Stable - Release Notes

    The full list of issues resolved for 6.4 Stable Release is presented below.

    • COR-878 - Simplify Typehandler4, remove readQuery(), readSubCandidate()
    • COR-873 - Simplify Typehandler4, remove classReflector(), getID(), linkLength()
    • COR-871 - .net packages should include the full version name (e.g.: db4o-net2-6.4.8.2078.msi, db4o-net2-6.4.8.2078.zip)
    • COR-870 - add svn.revision to Db4oVersion
    • COR-860 - NewTypehandler: Database file creation for upgrade tests
    • COR-859 - TypeHandler upgrade tests for short long float
    • COR-856 - TypeHandler upgrade tests for int
    • COR-855 - TypeHandler Version sets to replace MarshallerFamily
    • COR-854 - drs.dll product version is 1.0.0.0
    • COR-853 - dRS .net file size is not correct in the download center
    • COR-852 - .net document problems in 6.3 release
    • COR-851 - some tutorial problems in 6.3 release
    • COR-850 - Db4oService java doc: bad format
    • COR-849 - Javadoc problems in 6.3 release
    • COR-847 - No copyright in api document (html)
    • COR-846 - File size is not correct in the download center
    • COR-845 - .NET: svn revision should be last part of the assembly name
    • COR-844 - Report blocking compiler bugs to the mono team
    • COR-843 - Complete new TypeHandler reading for all Types
    • COR-838 - Factor out common Bloat bytecode abstraction library from NQ, TA, CLDC,...
    • COR-832 - 6.3 Production release check
    • COR-829 - .NET: Support for multiple assemblies
    • COR-827 - .NET: Change instrumentation from method to field access (self encapsulate field)
    • COR-826 - Java: Change instrumentation from method to field access (self encapsulate field)
    • COR-823 - .NET: add TA test suite to cruise control
    • COR-795 - dont instrument compiler generated classes
    • COR-794 - Test fails for db40 6.3 net 2.0(production version) Db4objects.Db4o.Tests-CF-2005 solution
    • COR-792 - Compilation fails for 6.3 production release net 1.1 Db4objects.Db4o.Tests-CF-2003 solution
    • COR-781 - FastCollections: New TypeHandler4 writing for .NET types
    • COR-780 - FastCollections: New TypeHandler reading primitive types Java
    • COR-778 - Create a 5-week plan for TP
    • COR-776 - Client/Server performance problem when operating on complex object
    • COR-772 - FastCollections: Simple TypeHandler4 writing for all types
    • COR-762 - Critical Performance Loss with higher BlockSize
    • COR-760 - No Native Query optimization for equals() comparisons on java.util.Date fields
    • COR-758 - Database file size unusually big
    • COR-755 - .NET: Proper handling of inheritance hierarchies
    • COR-753 - Unhandled exceptions in callbacks might bring the server down
    • COR-750 - NPE in Platform4.hasWeakReferences
    • COR-749 - Defragment does not correctly map String/Array addresses used in field index for inheritance hierarchies
    • COR-748 - Evaluate and estimate multi-transactional support for clustered ObjectContainers
    • COR-747 - Cleanup build scripts
    • COR-746 - Java Enum 'ordinal' and 'name' properties stored as null
    • COR-745 - Trunk: 3 tests fail on .NET Compact Framework 2.0
    • COR-744 - Retrieve failure with Map where Wrapper has Map property
    • COR-742 - FastCollections: Marshalling spike, one string field
    • COR-741 - In C/S mode the Object-reference for objectOnDelete is not activated
    • COR-739 - Removing array-reference in schema evolution corrupts database
    • COR-738 - NullPointerException while using Blobs in Client/Server mode
    • COR-736 - Predicate doesn't work correctly if the parameter of match method is declared as Object.
    • COR-735 - [SOLO] Db4objects.Db4o.Tests.CLI1.Aliases.TypeAliasesTestCase.TestTypeAlias
    • COR-734 - [SOLO] Db4objects.Db4o.Tests.Common.Exceptions.ObjectCanActiviateExceptionTestCase.Test
    • COR-733 - Test fail on .NET Compact Framework: Db4objects.Db4o.Tests.Common.CS.CallConstructorsConfigTestCase
    • COR-732 - Test fails for db4o-6.3-net1.r6967-Compact Framework
    • COR-729 - Test fails for db4o-6.3-net2.r6967-Compact Framework
    • COR-725 - Query#descend() returns null when trying to descend into an untyped collection for which no persisted objects exist
    • COR-717 - MClose should synchronize on global lock
    • COR-714 - StackOverflowException Occured when soda query executed using IConstraint
    • COR-710 - IndexOutOfBoundException triggered by ObjectSet#get() is not caught on the server
    • COR-709 - Sharpen.Net.Socket.Socket(string hostName, int port) throws "SocketException" when hostname is localhost
    • COR-702 - GenericReflector/Query problem.
    • COR-700 - Transient don't work
    • COR-699 - Concurrency issue with CallConstructorsConfigTestCase against JDK1.1.8
    • COR-694 - db4o doesn't open file in readonly mode when the database is configured as readonly.
    • COR-691 - switchToFile() shared client failure
    • COR-689 - 'Unique Field Constraint' rejecting the update of associated data to an existing key
    • COR-688 - Temp blob files are not deleted after running the test
    • COR-684 - Client/Server NullReferenceException in Query
    • COR-676 - Failed to get an object by ExtObjectContainer#getByUUID()
    • COR-674 - Integrate NQ optimization into OSGi build
    • COR-673 - Reflector for the Gigaspaces Adapter returning null values
    • COR-668 - MT: Pass all regression tests, possibly add missing concurreny tests
    • COR-667 - MT: Integrate concurrency test suite in build cycle
    • COR-666 - MT: Transaction-aware reference system
    • COR-665 - MT: Create ObjectContainer facade with own transaction
    • COR-664 - Multiple transactions for "In-process" mode
    • COR-663 - Object vanishes when another object is saved to db
    • COR-662 - ClassCastException on Objectcontainer.set() for db4o adapter for gigaspaces
    • COR-661 - ActivationExceptionBubblesUpTestCase failed in c/s mode.
    • COR-660 - Db4o doesn't close file handler after throwing file incompatible exception(Db4oException)
    • COR-655 - BTree query processor is slow for two level index
    • COR-653 - Check and update API docs where necessary
    • COR-652 - TSerializable/Java should use configured reflector information instead of default classloader
    • COR-651 - Get db4ounit jdk1.2 test suite to run green in OSGi environment
    • COR-645 - OSGi bundle reflector
    • COR-640 - FastCollections: Track database file size in Poleposition
    • COR-636 - Exception encountered when CallConstructors() is set to true in Client/Server mode
    • COR-635 - BackupStressTestCase failed intermittently
    • COR-634 - db4o throws OldFormatException but the file handler is not closed
    • COR-633 - Extra objects are instantiated in a callConstructors(false) / testConstructors(false) setting
    • COR-631 - TA blog entry
    • COR-630 - AllTestsJdk1_2 failed on jre <= 1.3
    • COR-628 - BTreeFreespace: Debug all leaks
    • COR-626 - Java NQ optimizer confusion about integer vs boolean return values
    • COR-625 - Create environment for Java NQ test cases against specified byte code sequences
    • COR-623 - db4oj test fails, many io related exception are thrown.
    • COR-622 - Remove references to db4on from build
    • COR-620 - demo showing db4o license agreement
    • COR-619 - SODA query Fail in embedded CS
    • COR-618 - Investigate handling of non-private field access for Transparent Activation
    • COR-615 - Deploy Java Transparent Activation instrumentation with build
    • COR-607 - deleting BLOB-files via Blob-interface
    • COR-605 - Hashtable Iterator
    • COR-601 - Many tests fail when blockSize is configured.
    • COR-600 - Improve freespace discard algorithm
    • COR-599 - ConfigurationItem support for augmenting the configuration before the ObjectContainer is open
    • COR-598 - db4oj test fails on linux
    • COR-596 - BTreeFreespace: Use Slot everywhere instead of address,length
    • COR-595 - DotnetSupport configuration item that adds the required aliases to support reading a .net generated data file from java
    • COR-592 - Implement Java byte code instrumentation for Transparent Activation
    • COR-590 - Create a Db4oAdmin instrumentation step for Transparent Activation
    • COR-588 - TA coverage of .net specific type system features
    • COR-586 - Collect information about OSGi spec/implementations, collect possible usage scenarios
    • COR-585 - OSGi compatibility
    • COR-584 - PersistentIntegerArrayTestCase fails in defrag mode
    • COR-583 - Querying stored classes should be read only, but triggers static class metadata updates
    • COR-582 - db4o embedded client thread doesn't exit until server socket timeout happens.
    • COR-577 - C/S connection leaves daemon thread hanging around
    • COR-576 - Eclipse return 13 when running javatocsharp.core.application
    • COR-575 - BTreeFreespace: Review old code and plan
    • COR-574 - BTreeFreespace: Test migration run from RAM-based Index system
    • COR-573 - BTreeFreespace: Drop old Index system
    • COR-571 - BTreeFreespace: Solve Hen-egg problem with own slot
    • COR-570 - BTreeFreespace: Get right-sized slot with next matching size
    • COR-569 - BTreeFreespace: Free and merge slots
    • COR-568 - BTreeFreespace: Create, Read and write BTreeFreeSpaceManager
    • COR-567 - BTreeFreespace: Standalone Freespace Test Case
    • COR-566 - BTreeFreespace: Extract FreespaceManager Interface
    • COR-565 - InvalidPasswordTestCase uses a fixed port
    • COR-564 - JDK_1_4#unlockFile method should invoke FileLock#release by reflection.
    • COR-563 - Setup cc Win
    • COR-558 - TransientClone test fails in batched c/s mode
    • COR-557 - NQ optimization will fail to recognize side effect assignments
    • COR-556 - Version number generator inconsistent in C/S mode
    • COR-555 - db4o test suite hangs when running in batched message mode.
    • COR-553 - NQ optimization ignores unoptimizable method calls in combined constraints
    • COR-552 - db4o tests fail on jre1.1.8
    • COR-549 - NQ optimization ignores constraints on method-local variables
    • COR-545 - 6.1 Callback discrepency problem
    • COR-543 - Delete/deleting callbacks are called in a separate transaction in client/server mode
    • COR-541 - additional db4o-6.1-nqopt.jar in classpath can lead to unexpectable search results
    • COR-540 - NPE in CreateQueryResult using embedded client
    • COR-539 - Array retrieved/read as null when a .Net database (a database created by .Net application) is read by a java application
    • COR-538 - Exception encountered when java database read by .Net application(exception encountered at .Net side only when java package name and .Net namespace are same for model classes )
    • COR-535 - Provide a way for EventRegistry to be notified whenever listeners subscribe to specific events
    • COR-534 - Diagnostics warning upon storing non TA enabled class instances in TA support mode
    • COR-531 - sharpen Transparent Activation project
    • COR-528 - Sharpen.IO.ByteArrayOutputStream and Sharpen.IO.ByteArrayInputStream are missing
    • COR-527 - Internal NullPointerException in embedded C/S mode
    • COR-524 - Refactor C/S messaging
    • COR-523 - Call committed() callback and test