Dienstag, 7. Juni 2011

 

Fehlerbehandlung

Bei folgendem Code-Stück sieht man nur die Ausgabe

RemoteException
sonst nichts. Keine weitere Information, um dem Problem auf die Schliche zu kommen.
public class Server {
    public static void main(String[] args) {
        try {
            LocateRegistry.createRegistry(1099);
            System.out.println("RMI-Registry erfolgreich gestartet");
        } catch (RemoteException ex) {
            System.out.println("Fehler beim Starten der Registry: " + ex);
        }
        try {
            DB db = new Data("fahrten.db");
            //System.out.println(((Data)db).records.size());
            DB d = (DB) UnicastRemoteObject.exportObject(db, 1099);
            System.out.println("1xx");
            Naming.rebind("Data", d);
            System.out.println("2xx");

            
            Header he = ((Data)db).getHeader();
            Header h = (Header) UnicastRemoteObject.exportObject(he, 1099);
            Naming.rebind("Header", h);


            System.out.println("Alles gebunden");


        } catch (RemoteException ex) {
            System.err.println("RemoteException");
        } catch (MalformedURLException ex) {
            System.err.println("MalformedURLException");
        }
    }
}
Ein einfaches System.err.println("RemoteException: " + ex.getMessage()); liefert schon etwas mehr hilfreiche Information;
RemoteException: remote object implements illegal remote interface; nested exception is: 
        java.lang.IllegalArgumentException: illegal remote method encountered: public abstract int data.Header.length()
In der Klasse Data findet man
public class Data implements DB, Serializable {

    private final int MAGIC_COOKIE = 4223;
    private Header header;
    private String fileName="";
    private ArrayList lockedRecNo;
    private int DataOffset; //166
Wenn man weiter sucht, findet man für Header das Interface
public interface Header extends Remote {
    public Field getField(int fID);

    public int length();

    public void addField(Field f);

}
Es fehlt schlicht und ergreifend die Implementierung zu Header. Das kann nicht funktionieren!

Die Implementierung muss UnicastRemoteObject erweitern, in Data sollte man statt private Header header; direkt die Implementierung verwenden: private Fields header;.

Die Implementierung von Fields beginnt etwa so:
public class Fields extends UnicastRemoteObject implements Header, Serializable {

    private ArrayList felder;

    public Fields() throws RemoteException {
        felder = new ArrayList(0);
    }
...
Unser Server sollte dann etwa so aussehen (ob das dann funktioniert, sei dahingestellt, aber die Exceptions sind geklärt):
public class Server {

    public static void main(String[] args) {
        DB db = null;
        try {
            db = new Data("fahrten.db");
        } catch (RemoteException ex) {
            System.err.println("RemoteException (new Data()): " + ex.getMessage());
        }
        try {
            LocateRegistry.createRegistry(1099);
            System.out.println("RMI-Registry erfolgreich gestartet");
        } catch (RemoteException ex) {
            System.out.println("Fehler beim Starten der Registry: " + ex);
        }
        try {
            DB d = (DB) UnicastRemoteObject.exportObject(db, 1099);
            Naming.rebind("Data", d);
        } catch (RemoteException ex) {
            System.err.println("RemoteException (rebind(Data)): " + ex.getMessage());
        } catch (MalformedURLException ex) {
            System.err.println("MalformedURLException: " + ex.getMessage());
        }
        try {
            Fields he = (Fields) ((Data) db).getHeader();
            Header h = (Header) UnicastRemoteObject.exportObject(he, 1099);
            try {
                Naming.rebind("Header", (Fields) h);
            } catch (MalformedURLException ex) {
                System.err.println("MalformedURLException (rebind(Header)): " + ex.getMessage());
            }
        } catch (RemoteException ex) {
            System.err.println("RemoteException: " + ex.getMessage());
        }
        System.out.println("Alles gebunden");
    }
}
Der langen Rede kurzer Sinn:

Für den Programmierer muss möglichst viel Information bereitgestellt werden. Für den Anwender hilft diese Information nichts und man muss einfache Fehlermeldungen anbieten (das ist hier auf dieser Ebene sowieso nicht möglich, denn die Software ist noch weit davon entfernt, einem Endanwender seine Dienste anzubieten).
Sinnvoll wäre es, die Exceptions zu loggen.
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
Am schlimmsten sind jedoch solche Konstrukte:

try {
                    while(true) {
                        records.add(read(nr));
                        nr++;
                    }
                } catch (RemoteException ex) {
                } catch (RecordNotFoundException ex) {
                }
Fehler sind praktisch unauffindbar. Auch nicht mit dem Debugger, weil man nicht einmal einen Breakpoint setzen kann, um die Variable ex zu inspizieren (die enthält ja Infos zur Exception).
Nachsatz: das alles kostet mich Stunden, die ich sinnvoller verbringen könnte. Einfach den Kandidaten durchfallen lassen, denn die Unit-Tests sind zu 93% (einer von dreizehn hat funktioniert) schief gegangen.

Labels: , ,


Kommentare:

Kommentar veröffentlichen

Abonnieren Kommentare zum Post [Atom]





<< Startseite

This page is powered by Blogger. Isn't yours?

Abonnieren Posts [Atom]