# Managed Bean Aufruf auf Stack legen



## halli_galli (17. Dez 2010)

Hallo Gemeinde,

ich möchte eine Rücksprungadresse auf einen Stack legen, bevor ich eine MB (Managed Bean) verlasse und eine andere MB aufrufe. 
Wenn die andere MB fertig ist, holt sie die Rücksprungandresse vom Stack und springt zur aufrufenden MB zurück.
Der Punkt ist, dass die verwendete MB von mehreren MBs verwendet werden soll und durch den Stack eine flexible Lösung her muss, was den Stack<Type> betrifft.

Das Verfahren habe ich bei Struts mehrfach erfolgreich angewendet, wobei da ein Stack<ActionForward> zum Einsatz kam. Im ActionForward ist der Request und der Action Name abgelegt.

Jetzt habe ich allerdings keine Ahnung, wechen Type ich dem Stack geben soll, 
um das Konstrukt mit JSF verwenden zu können.
Ich tendiere zu einem EL-Ausdruck, den ich auf den Stack<String> lege.

Hier ein kurzes Beispiel.

```
@ManagedBean
public class MasterController{
//in der Klasse ist bekannt, welche Managed Bean benoetigt wird, 


   private Stack<Type> stackUtil = FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("stackUtil");


   public void starteSlaveController(){
      // wäre hier ein EL-Ausdruck nicht ausreichend, der als String auf den Stack gelegt wird?
      stackUtil.push("#{MasterController.rechneWeiter}")
      
      ELContext elContext = FacesContext.getCurrentInstance().getELContext();
      ELResolver elResolver = context.getApplication().getELResolver();
      SlaveController sc = (SlaveController) elResolver.getValue(elContext, null, "slaveController");
      sc.startSlaveController();      
   }

   public String rechneWeiter(){
      return "fertig"
   }
}

@ManagedBean
public SlaveController{

    public void starteSlaveController(){
       private Stack<Type> stackUtil = FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("stackUtil");       

       berechne etwas...

       //springe zurück zur aufrufenden MB, ohne jedoch den Typ zu kennen 
       //und hier versagt mein einfacher EL-Ausdruck, der auf dem Stack liegt
       //denn zur Auflösung des EL-Ausdruckes benötige ich den Typ der ManagedBean
       //so ähnlich wie hier beim Aufruf der SlaveController MB aus der MasterController MB.
       stackUtil.pop("#MasterController.weiterRechnen");
    }
}
```

Hat jemand eine Idee oder schon mal etwas ähnliches gemacht? 
Ich vermute mal, dass ich auch den Request mit auf den Stack legen muss, wie es bei Struts der Fall ist, um evtl. Parameter aus dem Request holen zu können.

Vielen Dank schon mal für jeden konstruktiven Beitrag!


----------



## megaflop (19. Dez 2010)

Hallo,

Versteh ich das jetzt richtig: Du willst aus einer MB eine andere aufrufen und nach dem Aufruf wieder zurückspringen? Für mich hört sich das so an, als ob du das Rad neu erfinden willst 



> Der Punkt ist, dass die verwendete MB von mehreren MBs verwendet werden soll...



Beinhaltet diese MB, die von anderen MB's verwendet werden soll, Geschäftslogik? In diesem Fall würde ich dir empfehlen, diese Logik in eine EJB zu verpacken. Diese kannst du dann per @EJB-Annotation in deine ManagedBeans injizieren.

Solltest du schon JavaEE6 benutzen, so kannst du auch die @Inject-Annotation der CDI-Spezifikation nutzen - damit kannst du ManagedBeans in andere ManagedBeans injizieren.

Grüße,
Jonas


----------



## halli_galli (19. Dez 2010)

Hallo,

na das Rad will ich nicht neu erfinden, aber vielleicht habe ich mich etwas ungenau ausgedrückt, da es wahrscheinlich mehrere Punkte sind, die für mich noch nicht richtig klar sind.
Zuerst, die Geschäftslogik befindet sich bereits in EJBs, die per @EJB Annotation eingebunden wird.

Für mich ergeben sich im Moment zwei Probleme, die ich noch nicht eindeutig gelöst habe.

Wie soll der Aufruf einer anderen Managed Bean erfolgen:
Über wie nachfolgend beschrieben?
Oder über eine @ManagedProperty(value="#{kundeErfassenUCMB}") Annotation, wobei dabei allerdings darauf geachtet werden muss, dass die MB die verwendet werden soll in einem Scope liegt, der so lange oder länger besteht, wie wo die aufrufende MB liegt?
Oder über eine @Inject Annotation, wie eben von *megaflop* beschrieben ?

Wie funktioniert das mit der Navigation, wenn ich aus einer MB heraus, eine Methode einer anderen MB aufrufe? Ist es egal, ob ich die Navigations-Methode aus einem Facelet heraus oder aus einer anderen MB heraus aufrufe?


Zum einem habe ich zwar eine MB (Managed Bean) aus einer anderen MB mit 

```
ELContext elContext = FacesContext.getCurrentInstance().getELContext();
ELResolver elResolver = FacesContext.getCurrentInstance().getApplication().getELResolver();
KundeErfassenUCMB kundeErfassen = (KundeErfassenUCMB) elResolver.getValue(elContext, null, "kundeErfassenUCMB");
kundeErfassen.startKundeErfassen();
```
einbinden können, doch funktioniert in der zu verwendenden Managed Bean "kundeErfassenUCMB" die Navigation nicht, die aber angegeben ist.
Spreche ich aber diese MB aus einem Facelet heraus mit #{kundeErfassen.startKundeErfassen} an, funktioniert die Navigation von "startKundeErfassen", die ja den String "start_kunde_erfassen" zurück liefert.

Hier ist startKundeErfassen, eine leere Methode, die als Startadresse für einen Anwendungsfall dienen soll.

```
@ManagedBean(name = "kundeErfassenUCMB")
@SessionScoped
public class KundeErfassenUCMB {
    
    @EJB
    private KundeErfassenAL kundeErfassenAL;
public String startKundeErfassen(){
        //zum Testen leer, ggf. muss in anderen Fällen vor dem Anzeigen einer Tabelle, Geschäftslogik aufgerufen werden
        return "start_kunde_erfassen";      
    }
}
```

Die Navigationsregel sieht so aus
[XML]
<navigation-rule>
        <from-view-id>*</from-view-id>
        <navigation-case>
            <from-action>#{kundeErfassenUCMB.startKundeErfassen}</from-action>
            <from-outcome>start_kunde_erfassen</from-outcome>
            <to-view-id>/view/kunde/kundeErfassen/KundendatenEingeben.xhtml</to-view-id>
        </navigation-case>        
    </navigation-rule>
[/XML]

Noch kurz zum Verständnis. 
Jeder Anwendungsfall wird über eine Anwendungsfallname.startAnwendungsfall MB-Methode gekappselt.
Erst wenn das alles so funktioniert, spreche ich das mit dem Stack noch mal an.


----------



## Herr K. (30. Dez 2010)

Hallo,



			
				halli_galli hat gesagt.:
			
		

> Wie soll der Aufruf einer anderen Managed Bean erfolgen:
> Über wie nachfolgend beschrieben?
> Oder über eine @ManagedProperty(value="#{kundeErfassenUCMB}") Annotation, wobei dabei allerdings darauf geachtet werden muss, dass die MB die verwendet werden soll in einem Scope liegt, der so lange oder länger besteht, wie wo die aufrufende MB liegt?
> Oder über eine @Inject Annotation, wie eben von megaflop beschrieben ?



Hier würde ich Dir ganz klar zu 2. raten. Dies stellt eine spezielle Form der Depency Injection dar, bei der Du auf das ohnehin vorhandene Framework (JSF) zurückgreifst. Der Einsatz einer weiteren Annotation wie @Inject oder @EJB ist, wie bereits aus den Anmerkungen von megaflop hervorgeht, mit weiteren Abhängigkeiten verbunden. Ein klares Ziel sollte immer eine lose Kopplung sein. 

Gegen Deinen Ansatz sich über den aktuellen FacesContext ein Exemplar zu beschaffen spricht, dass gerade das Ziel des JSF Frameworks darin besteht Dir diese Arbeiten abzunehmen. Hast Du eine Annotation (oder analog ein Tag für XML basierte Konfiguration) welche die Abhängigkeit festlegt, wird das Framework dafür sorgen, dass das Objekt rechtzeitig und unter Berücksichtigung des korrekten Scope zur Verfügung steht.
Dein Code birgt die Gefahr, dass Du 

Die Abhängigkeit verbirgst, da man erst im Code suchen muss (abweichend vom erwarteten Standardverhalten und damit schlechter wartbar)
Explizit castest und einen Laufzeitfehler erzeugst
Du einen unnötigen Overhead erzeugst, das Framework wird ggf. eine bessere Verwaltung besitzen und auch prüfen ob das Objekt noch gültig ist


Wie funktioniert das mit der Navigation, wenn ich aus einer MB heraus, eine Methode einer anderen MB aufrufe? Ist es egal, ob ich die Navigations-Methode aus einem Facelet heraus oder aus einer anderen MB heraus aufrufe?

Das, was Du so schön als Navigation bezeichnest ist eigentlich eher eine Action. Eine JSF Action ist eine Methode, die keine Argumente besitzt und einen String zurückgibt. Der String bestimmt dabei das eigentliche Navigationsziel. Wenn Du jetzt also in einer JSF Action eine Methode einer anderen Backing Bean aufrufst, dann musst Du immer noch dafür sorgen, dass diese Bedingungen eingehalten werden.
Anders gesagt, Dein Code 

```
ELContext elContext = FacesContext.getCurrentInstance().getELContext();
ELResolver elResolver = FacesContext.getCurrentInstance().getApplication().getELResolver();
KundeErfassenUCMB kundeErfassen = (KundeErfassenUCMB) elResolver.getValue(elContext, null, "kundeErfassenUCMB");
kundeErfassen.startKundeErfassen();
```
ruft zwar eine Action auf, allerdings wird das Navigationsziel nicht nach außen weiter gereicht. Hier würde ein _return_ wahrscheinlich den gewünschten Effekt mit sich bringen.


----------



## halli_galli (31. Dez 2010)

Gut, mittlerweile (das letzte Posting von mir ist ja schon ein paar Tage her), habe ich mit der
@ManagedProperty(value="#{kundeErfassenUCMB}") Annotation gearbeitet.
Allerdings hat sich hier ein Problem aufgetan, welches ich noch nicht lösen konnte.

Wenn ich in der MB kundeAuswaehlenUCMB eine Property @ManagedProperty(value="#{kundeErfassenUCMB}") Annotation injeziere, kann ich auf Methoden der injezierten MB zugreifen.
Die "Navigation" funktioniert auch, da ich den Rückgabe-String der injezierten MB, in der Methode der aufrufenden MB als return zurück liefere.
Beim Aufruf der Methode der injezierten MB, springe ich in den Programfluss der injezierten MB, möchte aber später wieder zur anderen MB zurück springen.
Versuche ich aber in der ehemals injezierten MB kundeErfassenUCMB eine Property 
@ManagedProperty(value="#{kundeAuswaehlenUCMB}") zu injezieren, kommt leider eine Fehlermeldung. 

_Verwalteter Bean kundeAuswaehlenUCMB kann nicht erstellt werden. Die folgenden Probleme wurden gefunden: - Verwalteter Bean kundeAuswaehlenUCMB enthält zyklische Referenzen. Auswertungspfad: kundeAuswaehlenUCMB -> kundeErfassenUCMB -> kundeAuswaehlenUCMB._


Hier mal ein kurzer Quelltext dazu.

```
@ManagedBean(name = "kundeErfassenUCMB")
public class KundeErfassenUCMB {
    
    @EJB
    private KundeErfassenAL kundeErfassenAL;

    @ManagedProperty(value = "#{kundeAuswaehlenUCMB}")
    private KundeAuswaehlenUCMB kundeAuswaehlen;
    ...
}

@ManagedBean(name = "kundeAuswaehlenUCMB")
public class KundeAuswaehlenUCMB {
    
    @EJB
    private KundeAuswaehlenAL kundeAuswaehlenAL;

    @ManagedProperty(value = "#{kundeErfassenUCMB}")
    private KundeErfassenUCMB kundeErfassen;
    ...
}
```


----------



## Herr K. (31. Dez 2010)

Hallo, 

was genau ist denn die zugehörige Frage? ;-)

An sich sagt die Fehlermeldung schon alles was Du wissen musst, Du hast einen Zyklus (Kreis) und das ist nicht erlaubt. Ich nenne Deine Klassen vereinfacht "Erfassen" und "Auswaehlen", und lasse hier das Präfix "kunde" und das Suffix "UCMB" einfach mal weg.

Jetzt sagst Du, dass überall wo Du ein "Erfassen" Exemplar möchtest Du vorher ein "Auswaehlen" Exemplar erzeugen und injezieren möchtest. Das macht Java, kein Problem. Möchtest Du jetzt aber ein "Erfassen" Exemplar in "Auswaehlen" injezieren, dann siehst Du schon das Problem. 
Wird ein "Auswaehlen" Objekt erzeugt, erkennt JSF eine Abhängigkeit von "Erfassen" und erstellt ein solches Objekt. Dieses hat eine Abhängigkeit von "Erfassen", nach der Erstellung und vor dem injezieren muss jetzt also ein "Erfassen" Objekt erstellt und in das "Auswaehlen" injeziert werden. Nach Erstellung des "Erfassen" Objekts und vor Injektion in das "Auswaehlen" Objekt werden alle Abhängigkeiten erstellt und injeziert...
Du hast hier eine Endlosschleife, die nicht terminieren kann. Das erkennt JSF und weißt Dich auf die zyklische Abhängigkeit hin.

Ganz unabhängig von der Programmiersprache oder dem Framework solltest Du zyklische und im besonderen gegenseitige Abhängigkeiten immer vermeiden. Das ist einfach schlechter Stil, da Du eine sehr starke Kopplung und das Henne-Ei Problem hast. 

Es gibt immer verschiedene Möglichkeiten das Problem zu lösen. Über die Verwendung von Interfaces, die Auslagerung bestimmter Funktionen in eine dritte Klasse, die in beide Beans injeziert wird bis hin zum Neudesign der Klassen sind viele Ansätze möglich.
Was dabei am sinnvollsten ist bestimmt hauptsächlich die Anforderung. Die Frage ist also, was möchtest Du eigentlich genau machen? Ich bin relativ sicher, dass Du hier nur an der Erfahrung mit JSF scheiterst und nicht wirklich eine solche gegenseitige Abhängigkeit vorliegt.


----------



## halli_galli (31. Dez 2010)

Hallo K,

danke erst mal für die zwei für mich hilfreichen Postings!

Die Frage um die es hier geht, ist ja so einfach nicht zu stellen, sonst hätte ich nicht so viele Postings gebraucht, um auf den Punkt zu kommen.

Durch Struts bin ich es gewohnt, das am Ende einer Methode einer Actionklasse ein Forward zurückgeliert wird. 
Dieser Forward kann in der struts-config.xml so definiert werden, dass eine ander Actionklasse aufgerufen wird. 
Aufgrund der modellbasierten Entwicklung ist es jetzt so bei mir, dass einige Actionklassen nicht wissen, von wem sie aufgerufen werden.
Sie laden lediglich am Ende der Berechnung ein Action-Forward von einem Stack<Actionforward>, und damit eine Rücksprungandresse. 
Damit lassen sich diese Actionklassen ohne Kopplung von verschiedenen Actionklassen verwenden.
Das sind bei mir auf der modellbasierten Ebene Anwendungsfälle, die andere Anwendungsfälle verwenden.

So etwas will ich mit JSF machen.

Für die Actionklassen verwende ich Managed Beans. 
Für den Rücksprung aus einer Managed Bean Methode verwende ich einen String, der in einer Navigationsregel der faces-config.xml definiert ist (<from-outcome>startAwfKundeErfassen</from-outcome>).
Diesen String lege ich, bevor ich eine andere Managed Bean aufrufe, auf einen Stack<String>.
Wenn die Managed Bean wieder zu einem anderen Anwendungsfall zurückspringen soll, wird vom Stack der oberste Eintrag geladen.
JSF mapped dann über die faces-config.xml die Zieladresse, die leider - so weit ich informiert bin - immer nur eine Facelet sein kann und nicht eine Managed Bean, die dann zu einem Facelet weiter leitet.

Das funktioniert sowei alles ganz gut.

Jetzt ist es aber so, dass ich gerne, bevor ich ein Facelet anzeige, eine Managed Bean Methode auführen würde, quasi als Methode zum initialisieren eines ganzen Anwendungsfalles.

Jetzt habe ich mich nochmal etwas belesen und herausgefunden, das ich über eine If Bedingung einer Navigationsregel die Möglichkeit habe, über eine Navigationsregel, auf eine Managed Bean Methode zuzugreifen. 
Das könnte evtl. die Lösung meines Problems sein.

Ich hoffe, der Kern meines Problems wird jetzt besser ersichtlich.


----------



## Herr K. (1. Jan 2011)

Hallo halli_galli,

Ich denke dass ich tatsächlich Dein Problem nun besser verstehe. Allerdings muss ich leider sagen, dass ich denke Dein Hauptproblem liegt darin, dass Du hier gerne ein Struts-Verhalten 1:1 abbilden möchtest. 

Dazu möchte ich sagen, dass Struts und JSF (imho) sehr unterschiedliche Ansätze verfolgen. Wie Du schon sagtest ist Struts auf Actions ausgelegt, JSF hingegen vielmehr Komponentenorientiert.

Die Phasen eines JSF-Seitenaufbaus hast Du bestimmt schon in einer der vielen Dokumentationen/Grafiken gesehen. Auf die zugehörigen Details möchte ich hier auch gar nicht eingehen, im Prinzip ist aber einfach wichtig zu verstehen, dass eine JSF Action einfach immer genau aus dem Aufruf einer Methode oder dem direkten Sprung zu einer anderen Seite besteht. Beim (Neu)Laden der aktuellen Seite wird die EL ausgewertet und die Eigenschaften der Komponenten werden aus den Backing Beans gelesen. 

Hier ist es jetzt wichtig zu verstehen, was das ganze heißt. Eine Backing Bean sollte immer stark an eine JSF Komponente gebunden werden. Natürlich macht es jetzt keinen Sinn für jedes Textfeld eine eigene neue Backing Bean zu definieren, aber in der Regel setzt Du eine Webseite aus verschiedenen, logisch zusammengehörigen Bereichen zusammen. Alternativ kann es auch sein, dass Du eine Art Wizzard hast, bei dem sogar mehrere Webseiten eine zusammengehörige Komponente darstellen. Hast Du jedenfalls einen Scope, der sich sinnvoll von trennen und ggf. an anderer Stelle wiederverwenden lässt, dann würdest Du diesen als Komponente betrachten. 
Die Backing Bean speichert nun eben genau die Eigenschaften bzw. den Zustand dieser Komponente. Das gute dabei ist, dass Du diese Information auch an eine bestimmte Lebenszeit (die des Request, der Session oder gar der Applikation) binden kannst, aber das ist hier auch egal. 

Einen Aufrufstack und Rücksprünge solltest Du also bei JSF gar nicht erst andenken. Eine Webseite kann aus n Komponenten zusammengesetzt sein (Komponenten können natürlich auch selbst aus Komponenten zusammengesetzt werden). Alles was bei einer JSF Action nun getan wird ist Code ausführen, der den Zustand der Backing Beans anpasst und dann eine Webseite (das Navigationsziel) zu laden. 
Wird nun eine Webseite geladen, werden eben alle dort verwendeten Komponenten "gerendert" und dabei die Eigenschaften aus den gebundenen Backing Beans ausgelesen. 

Aus einer JSF Action solltest Du eigentlich nie auf eine andere JSF Action verweisen müssen. Das wäre (aus Sicht der Komponenten) eine eher ungünstige und unnötige Kopplung. Ein einfaches Workaround wäre es, dass Du die gemeinsam genutzten Zustände innerhalb der Domäne hältst (z.B. in einer ServiceKlasse) und von verschiedenen Backing Beans auf diese Klasse zugreifst. Hier kannst Du einerseits das Datum bereits in der Service Klasse für verschiedene Backing Beans aufbereiten und entsprechend abzulegen. Die Backing Beans können dann z.B. über unterschiedliche Methode die jeweils relevanten Elemente abfragen.
Alternativ kann natürlich auch jede Backing Bean die Logik enthalten auf die Belegungen zu reagieren. Letzteres ist aber aus verschiedenen Gründen eher ungünstig, vor allem, da hier die Logik unnötig weit oben in den Schichten sitzt und die Wiederverwendbarkeit stark eingeschränkt wird (für eine JSF Alternative müsstest Du diese Logik eben neu schreiben). 



			
				halli_galli hat gesagt.:
			
		

> Aufgrund der modellbasierten Entwicklung ist es jetzt so bei mir, dass einige Actionklassen nicht wissen, von wem sie aufgerufen werden.


Das verstehe ich ehrlich gesagt nicht. Eine Klasse sollte nie wissen müssen von wem Sie aufgerufen wird. Nehmen wir eine beliebige Java Standardklasse (o.B.d.A. sage ich mal StringBuilder). Einen StringBuilder kann ich in der Klasse FooBar die ich erst jetzt schreibe verwenden, ohne dass der Entwickler von StringBuilder wissen konnte, dass ich das tun werde. 

Ich verstehe halt noch nicht ganz warum Du explizit eine Rücksprungadresse benötigst. In einer Java-Methode kannst Du ja beliebig viele andere Methoden aufrufen. Ganz exemplarisch:

```
public String doFoo() {
  doSomething();
  doSomethingElse();
  return "TARGET";
}
```
Wird doSomething() ausgeführt, dann springt Java automatisch in die doFoo() Methode zurück und wird doSomethingElse() ausführen. Wozu sollte ich hier explizit eine Rücksprungadresse angeben?

Natürlich kannst Du auch eine dynamische Liste oder einen Stack pflegen, der alle aufzurufenden Methoden führt. Dieser würde imho aber eher in die Domäne gehören und damit in die Schicht unter JSF. Hier kannst Du dann z.B. ein Interface definieren, dass eine Action-Methode deklariert, die z.B. selbst eine Liste/ einen Stack von weiteren Aktionen (vom Typ des Interface) zurückgibt. Dann kannst Du eine Dispatcher-Klasse schreiben, die einfach einen solchen Stack bekommt, die erste Aktion entnimmt, die Action-Methode ausführt und die Ergebnismenge auf dem Stack ablegt. Das ganze eben in einer Schleife bis keine Aktion mehr übrig ist.


```
public interface IAction {
  public Stack<IAction> executeAction();
}

public class ActionDispatcher {
  public void dispatch(final Stack<IAction> actions) {
    while (!actions.empty()) {
      final IAction action = actions.pop;
      actions.addAll(action.executeAction());
    }
  }
}
```

Ich hoffe ich habe Dich jetzt richtig verstanden.


----------



## halli_galli (1. Jan 2011)

Danke K, für die ausführliche Beschreibung. Diese hat mich wieder etwas näher an das JSF-Konzept herangeführt. 
Ich versuche mal das Ganze abstrakter zu formulieren, in der Hoffnung, dann besser verstanden zu werden.

Zum Zitat:
_Aufgrund der modellbasierten Entwicklung ist es jetzt so bei mir, dass einige Actionklassen nicht wissen, von wem sie aufgerufen werden._

Ich habe in der modellbasierten Entwicklung mehrere Anwendungsfälle (AWFs) per UML definiert, die miteinander durch Beziehungen verbunden sind.
Die Modellierung erfolgt möglichst so modular, dass nichts doppelt gemacht wird, deshalb die Beziehungen der AWF.
Bei den Beziehungen zw. AWFs wird zwischen Include- und Extend-Beziehungen unterschieden (UML Grundlagen).


Durch eine Include-Beziehung wird ein AWF von einem anderen AWF verwendet, ohne das der verwendete AWF genau weiß, wer ihn verwendet.
Der Haupt-AWF braucht, um seine Funktionalität gewährleisten zu können, zwingend die AWFs, die über Include eingebunden werden (auf der modellbasierten Ebene).
Der über Include verwendete AWF legt ein Rückgabeobjekt (möglichst ein DTO) in den Request- oder Session-Scope, welches vom aufrufenden AWF später verwendet wird.

Doch bevor der zu verwendende AWF aufgerufen wird, muss noch eine Rücksprung-Ziel gespeichert werden, damit nach der Verwendung des includierten AWF, der Haupt-AWF fortgesetzt werden kann.
So ist es auf der modellbasierten Ebene vorgesehen. 
Es geht also, um das ganze mal auf den Punkt zu bringen, um einen Rücksprung in den Programmfluss des Haupt-AWF und zwar an ganz bestimmter Stelle.

Was gibt es nun für Rücksprung-Stellen in JSF? Eigentlich nur Facelets.
(ein AWF kann aus mehreren Facelet Seiten bestehen). 
Soweit ist das nun kein Problem, hier würde ich einen String einer Navigationsregel auf den Stack legen, wie oben von mir bereits beschrieben, der durch JSF mit der faces-config.xml aufgelöst wird.
Hier mal ein kleines Beispiel einer MB Methode, die am Ende eines Include-AWF den Rücksprung für eine Action Methode der MB lädt.

```
private String ladeRuecksprung(){

        String forward = StackUtil.popAwfReturnStack();
        if (forward==null){            
            //Todo: Fehlermeldung generieren            
            JsfUtil.addErrorMessage(ResourceBundle.getBundle("/Bundle").getString("Fehler_Ruecksprung"));
            return "fehlerseite";
        }else{            
            return forward;
        }
    }
```

Du (K) hasst ja schon beschrieben, dass durch die Expression Language alles aus der Managed Bean geladen wird und somit -wie bei Struts - eine Initialisierung durch ein Action Aufruf (Actionklasse.methode) entfällt. Das ist wirklich sehr ergonomisch, wenn man vorher mti Struts gearbeitet hat.

Ob ich jetzt mehrere Managed Beans pro Facelet oder eine MB pro Facelet verwende, ist für mich jetzt erstmal sekundär. 
Recht hasst du da aber sicher mit der Komponentenbasierung.

Hoffe ich habe mich jetzt verständlicher ausgefrückt, so dass du verstehen kannst was ich mit Rücksprung meine.
Jedenfalls finde ich es super, dass sich wenigstens einer richtig an der Diskussion beteiligt.


----------



## Herr K. (2. Jan 2011)

Hallo halli_galli, 

nichts zu danken, dafür sind Foren ja da.



			
				halli_galli hat gesagt.:
			
		

> Durch eine Include-Beziehung wird ein AWF von einem anderen AWF verwendet, ohne das der verwendete AWF genau weiß, wer ihn verwendet.
> Der Haupt-AWF braucht, um seine Funktionalität gewährleisten zu können, zwingend die AWFs, die über Include eingebunden werden (auf der modellbasierten Ebene).


Bis hierhin alles klar!



			
				halli_galli hat gesagt.:
			
		

> Der über Include verwendete AWF legt ein Rückgabeobjekt (möglichst ein DTO) in den Request- oder Session-Scope, welches vom aufrufenden AWF später verwendet wird.


Ok, mal ohne Beschränkung der Allgemeinheit, sagen wir dass es sich bei der Rückgabe um ein DTO handelt. Warum wird dieser Wert in das Request oder Session Objekt gelegt? Was spricht hier gegen die Verwendung eines Rückgabewertes einer "normalen" Java Methode? 



			
				halli_galli hat gesagt.:
			
		

> Doch bevor der zu verwendende AWF aufgerufen wird, muss noch eine Rücksprung-Ziel gespeichert werden, damit nach der Verwendung des includierten AWF, der Haupt-AWF fortgesetzt werden kann.
> So ist es auf der modellbasierten Ebene vorgesehen.


Den letzten Satz kann ich leider nicht ganz zuordnen. Ein Modell legt doch eigentlich keine Implementierungsdetails fest. Alles was Dein Anwendungsfall Dir beschreibt ist, welcher Anwendungsfall eintreten kann, wer die beteiligten Akteure sind und auf welche Anwendungsfälle dabei zurückgegriffen wird. Ob, wie und wann dabei ein Rücksprung realisiert wird ist doch eigentlich dem Modell erstmal egal. 

Ich denke wir können die ganze Diskussion etwas vereinfachen, wenn wir die Abstraktion etwas senken. Hast Du vielleicht ein Beispiel für einen Anwendungsfall, der sich eben aus mehreren anderen zusammen setzt? Ich denke an einem solchen Beispiel lässt sich das wohl leichter erklären.

Für mich stellt sich eben weiterhin die Frage warum Du den Rücksprung in JSF machen möchtest. Deine _ladeRuecksprung_ Methode verwendet doch erstmal nichts, was Du nicht auch in "normalem" Java analog verwenden könntest. Ich denke hier noch nicht vollständig Deine Intention verstanden zu haben. Also was Du machen möchtest schon, aber mir fehlt noch die Begründung für das Warum. 
Wie gesagt, vielleicht wird das am Beispiel nochmal klarer


----------



## halli_galli (2. Jan 2011)

Hallo K,

zum Zitat:
_Der über Include verwendete AWF legt ein Rückgabeobjekt (möglichst ein DTO) in den Request- oder Session-Scope, welches vom aufrufenden AWF später verwendet wird.
_ 

Ist nicht die Kopplung geringer, wenn der Include AWF das Rückgabe-Object in einen Scope legt?
Will man aus bestimmten Umständen das Webframework wechseln, ist es dann günstiger, wenn der Datenaustausch der AWFs sich auf die Behälter beschränkt und nicht Framework-spezifisch funktioniert.
Auch fällt somit die Abkappselung eines AWF von anderen AWF leichter, denn es soll von außen nicht einfach möglich sein, in den Programmfluss eines AWF einzusteigen.

Aber vielleicht denke ich immer noch zu sehr in der höheren Abstraktionsebene.

zum Zitat:
_Doch bevor der zu verwendende AWF aufgerufen wird, muss noch eine Rücksprung-Ziel gespeichert werden, damit nach der Verwendung des includierten AWF, der Haupt-AWF fortgesetzt werden kann.
So ist es auf der modellbasierten Ebene vorgesehen._

Im Grunde kommen bei meinem modellbasierten Verfahren mehrere Modelle und Modelltransformationen zur Anwendung. 
Die Entwicklung erfolgt von der Abstratkionsebene der Anforderungsermittlung über weitere Transformationsschritte, bis schließlich zur Entwurfsspezifikation, die eine einfache und direkte Implementierung ermöglicht.
In der Entwurfsspezifikation sind Implementierungsdetails der Zielplattform enthalten (Java EE 6 mit JSF als Webframework).

Klar wäre ein Beispiel hier jetzt treffender, aber mir läuft etwas die Zeit davon.
Außerdem ist die programmatische Umsetzung des Projektes eh nur sekundär und deshalb wird hier nicht jedes Detail auf die Goldwaage gelegt. 
Der Kern ist die Anwendung der modellbasierten Entwicklung und Demonstration an einem einfachen Beispiel. 
Wie ich nun den Rücksprung gestalte, ist im Grunde wahrscheinlich ziemlich egal. 
Ich werde deshalb, wie bei Struts auch, bei JSF die Navigationsregeln für das Rücksprungziel verwenden.
In der Anwendungslogik (EJB) sollen nur Details der Fachdomäne enthalten sein und keine Details, wie der Rücksprung eines AWF erfolgt. 
Aber wie bei den DTOs, gibt es hier wahrscheinlich verschiedene Lösungsansätze, mit jeweils Vor- und Nachteilen.


----------

