# Asynchrone Methoden nacheinander aufrufen



## Fabulus (3. Mai 2012)

Hallo,

ich habe hier eine GWT-Anwendung, welche auf eine Datenbank via Hibernate zugreift.
Für dem Datentransfer benutze ich RPCs.
Ich möchte einen Datensatz aus einer Datenbank auslesen, und in eine Liste speichern und zurückgeben.

Ich zeig euch mal den Code:

```
public List<DataObjectDTO> loadObjectList()  {
		final List<DataObjectDTO> objects = new ArrayList<DataObjectDTO>(0);

 // rufe die Methode zum Laden auf Serverseite auf
		DBConn.getService().loadAllObjects(new AsyncCallback<List<DataObjectDTO>>() {
			
			@Override
			public void onSuccess(List<DataObjectDTO> result) {
				
				for(DataObjectDTO gr : result) {
					objects.add(gr);
				}
				

// lass hier die Größe der Liste ausgeben (1)
			}
			
			@Override
			public void onFailure(Throwable caught) {
			
				
			}
		});
		
// Lass hier erneut die Listengröße zurückgeben (2)
		return objects;
	}
```

Wenn ich bei (1) die Größe zurückgeben lasse, ist dieses Ergebnis richtig wie erwartet.
Bei (2) ist die Luste aber leer, weil die Methode ja parallel aufgerufen wird...

Wie kann ich es so machen, dass gewartet wird, bis die Liste komplett gefuellt ist?


----------



## SlaterB (3. Mai 2012)

final Object monitor = new Object();

warten:
monitor.wait();

aufwecken:
monitor.notify(); am Ende der AsyncCallback-Aktioen,
jeweils in synchronized-Blocks, die dir hoffentlich was sagen

paar Gefahren gibt es, notify vor dem wait wäre schlecht, aber so schnell wird das wohl nicht ausgeführt,
nicht ausgeführtes notify() wegen Exception wäre auch schlecht

nicht ewig zu warten sondern nur bestimmte Zeiten und dann gegebenenfalls selber anders erscheinen
wäre die etwas sichere Variante


----------



## Marcinek (3. Mai 2012)

Indem on sucess wiederum ein event feuert, worauf deine Komponenten warten.

==> Du musst das also in die on success methode implementieren.


----------



## Fabulus (3. Mai 2012)

Also soll ich die wait() und notify() auf die Liste anwenden?
Ich weiss, was synchronized-Blöcke sind, habe sie jedoch noch nie benutzt...

Habe es jetzt so testweise implementiert:

```
public List<DataObjectDTO> loadObjectList()  {
        final List<DataObjectDTO> objects = new ArrayList<DataObjectDTO>(0);
 	synchronized (this){
		try {
			objects.wait();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

 // rufe die Methode zum Laden auf Serverseite auf
        DBConn.getService().loadAllObjects(new AsyncCallback<List<DataObjectDTO>>() {
            
            @Override
            public void onSuccess(List<DataObjectDTO> result) {
                
                for(DataObjectDTO gr : result) {
                    objects.add(gr);
                }
                synchronized(this) {
				       objects.notify();
		        }
            }
            
            @Override
            public void onFailure(Throwable caught) {
            
                
            }
        });
        return objects;
    }
```

Was kommt in die Klammern von synchronized?
Ich bekomme beim Starten der Anwendung folgende Fehler:

```
[ERROR] Line 516: The method wait() is undefined for the type List<DataObjectDTO>
[ERROR] Line 517: No source code is available for type java.lang.InterruptedException; did you forget to inherit a required module?
[ERROR] Line 532: The method notify() is undefined for the type List<DataObjectDTO>
```

Ich denke, ich muss in der xml-Datei ein bestimmtes Modul einbinden, oder? Jedenfalls war dies immer der Fall, wenn kein Sorcecode für etwas gefunden wurde...

Edith sagt:


> Multithreading and Synchronization: JavaScript interpreters are single-threaded, so while GWT silently accepts the synchronized keyword, it has no real effect. Synchronization-related library methods are not available, including Object.wait(), Object.notify(), and Object.notifyAll(). The compiler will ignore the synchronized keyword but will refuse to compile your code if the Object's related synchronization methods are invoked.



Hm, damit gehts dann wohl leider nicht...


----------



## SlaterB (3. Mai 2012)

das sind ja äußerst merkwürdige Fehlermeldungen für Methoden der Klasse Object, die nun wirklich jedes einzelne Java-Objekt haben sollte,

wenn diese nicht vorhanden sind, warum auch immer, sehe ich als Alternative nur noch Thread.sleep(),
ist das erlaubt? sonst wäre Warten nicht gut hinzubekommen 
(von allen möglichen anderen Problemen, die so etwas merkwürdiges impliziert, abgesehen)

ist es denkbar, dass die Methode nichts zurückgibt und onSuccess() stattdessen irgendwas aufruft?

-------

unter Ignorierung der Fehlermeldungen noch weiter zu dem Thema, auch wenn vielleicht nicht zu verwenden:

> Also soll ich die wait() und notify() auf die Liste anwenden?
in zwei Hinsichten bemerkenswert, erstens habe ich doch geschrieben worauf du wait/ notify aufrufen sollst,
ein neues Object monitor,

eine vorhandene Liste zu nehmen ist allerdings durchaus eine bessere Alternative von dir,
erstaunlich ist dann aber für mich, dass du nicht die lokale Variable objects nimmst sondern groups, welches im geposteten Code gar nicht weiter erklärt wird

----

in jedem Fall falsch wäre, das wait() VOR dem loadAllObjects() zu stellen, wenn DAVOR gewartet wird, dann kommt der AsyncCallback doch nie zur Arbeit, nie werden Listen geladen und vielleicht notify() aufgerufen usw.,
das wait() muss selbstverständlich dahinter, am Ende der Methode vor der Rückgabe

erst das Taxi anrufen, dann an der Straße warten, nicht umgekehrt

--------

edit:
also mit Thread.sleep(Zeit x) in einer Schleife könntest du auf normaleren Wege warten,
z.B. bis ein boolean von der Methode gesetzt wird (finale lokale boolean[]-Variable der Lönge 1)

bei 'single-threaded' ist allerdings nicht zu erwarten, dass dann AsyncCallback überhaupt je drankommt, geht also wohl auch nicht..


----------



## Fabulus (3. Mai 2012)

groups war das gleiche Objekt, hab es nur umbenannt gehabt.

Das mit dem Taxi und dem wait klingt logisch, danke!

Ich wollte es jetzt so versuchen:

```
public List<DataObjectDTO> loadObjectList()  {
        final List<DataObjectDTO> objects = new ArrayList<DataObjectDTO>(0);
 	final boolean[] wait = new boolean[1];
	wait[0] = false;
 // rufe die Methode zum Laden auf Serverseite auf
        DBConn.getService().loadAllObjects(new AsyncCallback<List<DataObjectDTO>>() {
            
            @Override
            public void onSuccess(List<DataObjectDTO> result) {
                
                for(DataObjectDTO gr : result) {
                    objects.add(gr);
                }
               wait[0] = true;
            }
            
            @Override
            public void onFailure(Throwable caught) {
             wait[0] = true;
            }
        });

      while(!wait[0]) {  }

        return objects;
    }
```

Dies endet aber in einer Endlosschleife und das Skript bricht ab..
Was ich merkwürdig finde, ist, dass JavaScript das ganze Singlethreaded ausführt, aber die DB-Abfragen parallel laufen.


----------



## SlaterB (3. Mai 2012)

im Normalfall wiederum sollte in Zeile 23 ein sleep in die Schleife, 
aber wie gesagt wegen Singlethreaded wohl nicht drin

so merkwürdig ist das nicht, DB ist was anderes als das Java-Programm,
lasse also die Methode hier enden, du kannst nicht schon mit den Daten rechnen, wer immer der Aufrufer ist, muss sich auch mit Mittagspause zufrieden geben

am Ende von onSuccess() kannst du eine andere Methode aufrufen, dann gehts weiter


----------

