# DB4O in Tomcat



## DarkAngelfire (14. Jan 2013)

```

```
Hallo, 
ich hoffe ihr könnt mir bei meinem Problem helfen:
Ich bin dabei eine Anwendung in Java zu schreiben. Sie soll REST Services als Schnittstellen anbieten und läuft daher mit Jersey in Tomcat. Zum Speichern der Objekte dachte ich an DB4O (oder gibt es eine andere einfache Möglichkeit?). Daher habe ich DB4O als separates Projekt in Eclipse als Java Anwendung angelegt und betreibe die DB im Client/Server Modus. Zum testen habe ich eine Java SE Anwendung geschrieben...das klappt auch.

Wenn ich nun die selbe Klasse in den Tomcat schiebe und Aufrufe kommt es sehr häufig zu Exceptions. Sehr selten gelingt ein "store" oder ein "query" und das ohne! etwas am Code zu ändern.

Der Fehler:

```
Jan 14, 2013 10:59:01 AM com.sun.jersey.spi.container.ContainerResponse mapMappableContainerException
SEVERE: The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
java.lang.ClassCastException: entities.MeineKlasse cannot be cast to com.db4o.reflect.generic.GenericObject
	at com.db4o.reflect.generic.GenericField.get(GenericField.java:36)
	at com.db4o.internal.reflect.StrictFieldAccessor.get(StrictFieldAccessor.java:13)
	at com.db4o.internal.FieldMetadata.getOrCreate(FieldMetadata.java:555)
...
```


```
import com.db4o.*;
import com.db4o.cs.*;
import com.db4o.cs.config.*;
import com.db4o.messaging.*;
/**
 * starts a db4o server with the settings from {@link ServerInfo}.
<br>
 * <br>
 * This is a typical setup for a long running server. <br>
 * <br>
 * The Server may be stopped from a remote location by running
StopServer. The
 * StartServer instance is used as a MessageRecipient and reacts to
receiving an
 * instance of a StopServer object. <br>
 * <br>
 */
public class StartServer implements ServerInfo, MessageRecipient {
    /**
     * setting the value to true denotes that the server should be
closed
     */
    private boolean stop = false;
    /**
     * starts a db4o server using the configuration from {@link
ServerInfo}.
     */
    public static void main(String[] arguments) {
        new StartServer().runServer();
    }
    /*** opens the ObjectServer, and waits forever until close() is
called or a
     * StopServer message is being received.
     */
    public void runServer() {
        synchronized (this) {
            ServerConfiguration config =
Db4oClientServer.newServerConfiguration();
            // Using the messaging functionality to redirect all
            // messages to this.processMessage
            config.networking().messageRecipient(this);
            //config.file().lockDatabaseFile(false);
            ObjectServer db4oServer =
Db4oClientServer.openServer(config
                    , FILE, PORT);
            db4oServer.grantAccess(USER, PASS);
           
            // to identify the thread in a debugger
Thread.currentThread().setName(this.getClass().getName());

           
 // We only need low priority since the db4o server has
            // it's own thread.
            Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
            try {
                if (!stop) {
                    // wait forever for notify() from close()
                    this.wait(Long.MAX_VALUE);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            db4oServer.close();
        }
    }
    /**
     * messaging callback
     *
     * @see
com.db4o.messaging.MessageRecipient#processMessage(MessageContext,
     *      Object)
     */public void processMessage(MessageContext con, Object message) {
         if (message instanceof StopServer) {
             close();
         }
     }
     /**
      * closes this server.
      */
     public void close() {
         synchronized (this) {
             stop = true;
             this.notify();
         }
     }
 }
```

Die Klasse für den Datenbankzugriff:

```
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.cs.Db4oClientServer;

public class Database {
	private ObjectContainer container = null;

	public ObjectSet<Object> queryObject(Object obj){
				ObjectSet<Object> result = getDatabase().queryByExample(obj);
				return result;	
	}
	
	
	public void storeObject(Object o){		
				getDatabase().store(o);

	}
	
	private ObjectContainer getDatabase(){
		if(container==null)
			container = Db4oClientServer.openClient("localhost", 50000, "test", "test);
		
		return container;
	}
	
	public void closeDatabase(){
		if(container !=null){
			container.close();
			container = null;
		}
	}
}
```

Und das REST Interface:

```
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;


import com.db4o.Db4o;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;

import database.*;
import entities.MeineKlasse;


@Path("/service")
public class Service{
	
	@POST
	@Produces(MediaType.TEXT_PLAIN)
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	public String Service(@FormParam("id") String id){
		
		Database data = new Database();

		//Eventuell vorhandes Objekt suchen und updaten
		MeineKlasse dummy = new MeineKlasse(id);

		ObjectSet<Object> obj = data.queryObject(dummy);
		MeineKlasse klasse;
		for(int i=0;i<obj.size();i++){
			klasse= (MeineKlasse)obj.get(i);
			if(klasse.getId().equals(id)){
				klasse.setId(id);
			}
		}
		klasse= dummy;
		klasse.setId(id);
		
		data.storeObject(klasse);

                //Abfrage, ob Objekt gespeichert wurde
		ObjectSet<Object> objs = data.queryObject(new MeineKlasse());
		MeineKlasse s;
		for (int i=0;i<objs.size();i++){
			s=(MeineKlasse)objs.get(i);
			System.out.println("...");
		}
		
		return id;
	}
}
```

Was mache ich falsch? Oder gibt es eine andere einfache Möglichkeit der Speicherung?

Vielen Dank schonmal für eure Hilfe

Viele Grüße,
DarkAngelfire


----------



## turtle (14. Jan 2013)

Anscheinend liegt dein Schwerpunkt auf REST Services und nicht auf Persistenzfragen.

Daher würde ich dieses weitestgehend im Projekt ausklammern. Ich schlage vor, dass Du ein Interface baust, mit dem dein REST Service arbeiten soll.

Dann kannst Du eine simple Implementierung machen, die alle Aufrufe an In-Memory-Objekte erledigt und diese noch einfach serialisieren, damit die Daten auf Festplatte stehen. Eine andere Implementierung könnte auf eine relationale DB durchführen und wieder eine Realisierung mit db4o.

So bist Du flexibel und kannst bei Bedarf auf eine Persistenzschicht wechseln die dir zusagt oder in die du dich eh einarbeiten wolltest.

Zumindest kannst Du dich zunächst um deinen REST Service kümmern und dich nicht um DB-Fragen kümmern.


----------



## andy82 (22. Jan 2013)

Ich hatte mal Projekt mit DB4OJ gearbeitet und hier sind ein Paar Erfahrungen

gegenüber rel. DB spart man in wrapper schicht viel Arbeit (statt SQL-Befehl zu schreiben), aber :bae: mit Vorsicht zu geniessen. DB4O speichert die Object-Struktur mit (SuperClass, Interface, Parameter...) und wie, was genau...? Wir können nicht nachvollziehen. Sollten wir später die Objekte mal seine Strukturen ändern (was sich aber oft während einer Projekt passiert!), es sei neue Interface, mal neue Parameter (z. B. Object Adresse wird Param PLZ hinzugefügt...), dann ist die vorhandene Datenbank unlesbar.

Die Wrapper-Objects, die durch store() in die DB speichert, sollen also sich nicht beliebig seine Struktur ändern. Daher sollen sie möglich von Business-Schicht (Anwendungsschicht) fern und umgekehrt sollen business-Objects niemals direkt durch store(), delete()...mit DB kommunizieren lassen. Jede store(WrapperObject), retrieve(WO), delete(WO) in Wrapper-Schicht... sollen entsprechende Methoden store(BussinesObject), select(BO), delete(BO)... in Persistence-Schicht zuordnen und umgekehrt. Somit können wir bussiness-Objects und seine Struktur während einer Projekts oder später ändern und anpassen.

Also braucht mal schon gewisse Gedanke am Anfang einer Projekt, wie die Wrapper-Objects aufgebaut sind.


----------

