# JSF - Mehrere Message-Bundles verwenden



## Berndt (3. Jul 2007)

Hallo,
habe eine JSF-Anwendung in welcher mehrere Message-Bundles eingebunden werden, wie z.B.:


```
<application>
		<locale-config>
			
			<default-locale>de</default-locale>
		</locale-config>
		
		<message-bundle>messages_anwendung1</message-bundle>
		<message-bundle>messages_anwendung2</message-bundle>
		<message-bundle>messages_anwendung3</message-bundle>
   
	    <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
	</application>
```

Das Problem ist nun, das jede Message-Datei eigene Fehlermeldungen für die Validierung hat. Also z.B.:

*messages_anwendung1*

```
javax.faces.component.UIInput.REQUIRED=Fehlende Eingabe, bitte wählen Sie eine Antwort aus!
```


*messages_anwendung2*

```
javax.faces.component.UIInput.REQUIRED=Eingabe fehlt
```


*messages_anwendung3*

```
javax.faces.component.UIInput.REQUIRED=Ne so gehts nicht...
```


usw..

Das Problem ist nun das ich nicht weis wie ich meiner jeweiligen Anwendung beibringen soll, welches Message-Bundle bei der Validierung verwendet werden soll. Vermute mal man kann ein Message-Bundle einer Managed-Bean zuordnen?

Kann mir da jemand bitte helfen?


----------



## Guest (3. Jul 2007)

Du kannst das zu verwendende Bundle in deiner Backingbean auswählen und dann den Text in einer entsprechenden Methode oder in einem Attribut zurückgeben:


Java EE 5 Tutorial: Performing Localization


----------



## Berndt (3. Jul 2007)

Also ich raff das gerade nicht. Wie kann ich dem Validator sagen das beim Fehler "javax.faces.component.UIInput.REQUIRED" der mir die Nachricht aus dem Message-Bundle "messages_anwendung2" holen soll? Wie fange ich diesen automatischen Vorgang ab? Muss ich eine Methode in meiner Managed-Bean überschreiben?


----------



## Guest (3. Jul 2007)

Oh, das habe ich falsch verstanden. Das was du vor hast ist ja eigentlich nicht der Sinn von der Lokalisierung, die Angeboten wird. Da wirst du dir wohl deine eigenen Validatoren schreiben müssen, die das entsprechende ResourceBundle verwenden


----------



## Berndt (3. Jul 2007)

Das bedeutet also ich muss für jeden Fehler der auftreten kann, einen eigenen Validator schreiben? 

Hm wenns so ist würde ich das so machen, das ich in meiner Bean eben diverse Methoden anlegen würde wie z.B. "validateInput", "validateEmail"... und diese dann die Fehlermeldung aus dem jeweiligen Message-Bundle ziehen würden.

Ist aber ziemlich aufwendig. Lieber wäre es mir man könnte angeben das die Bean XYZ genau das Message-Bundle "messages_anwendung2" verwenden soll und die Bean ABC eben das Message-Bundle "messages_anwendung1". 

Bisher überschreiben sich die Message-Bundles mit ihren Fehlertexten. Wenn jedes Bundle den Fehlertext für "javax.faces.component.UIInput.REQUIRED" implementiert, dann gewinnt das Message-Bundle, welches als letztes in der faces-config.xml eingetragen worden ist.


----------



## SnooP (3. Jul 2007)

?Was für versch. Anwendungen?
Es wird doch aufgrund des jeweiligen Locales bereits entschieden, welches Ressource-Bundle verwendet wird... im einfachsten Fall kann man also den Browser abfragen und bekommt den entsprechenden Locale-String zurück, der automatisch von JSF benutzt wird.. je nachdem welche ressource-bundle-Dateien da sind wird die best-passende benutzt bis ein key gefunden wurde... 

das heißt: du brauchst für all deine locales unterschiedliche dateien:
MessageResources_en.property
MessageResources_en_US.property
MessageResources_de.property

und dafür die drei locales und als message-bundle in der jsf:
de.dein.package.MessageResources

Alternativ kann man natürlich auch ein konkretes Local beim Zugriff auf die messages nutzen... - das ist z.B. sehr gut im iX-Tutorial zu JSF zum Thema I18N beschrieben.


----------



## Berndt (3. Jul 2007)

Es geht hier nicht um Locales. Ist alles in Deutsch. Geht nur darum das verschiedene Beans vorhanden sind, und jede Bean ihr eigenes Message-Bundle benötigt. 
Hab diverse Webseiten in der faces-config.xml drinnen. Jede Webseite hat ihre eigene Beans. Bei Webseite X heisst der Standartfehler halt: "Passt so nicht", bei Seite Y dann eben "Fehler, ..." usw.


----------



## WeirdAl (3. Jul 2007)

Hi,



> Hm wenns so ist würde ich das so machen, das ich in meiner Bean eben diverse Methoden anlegen würde wie z.B. "validateInput", "validateEmail"... und diese dann die Fehlermeldung aus dem jeweiligen Message-Bundle ziehen würden.
> 
> Ist aber ziemlich aufwendig. Lieber wäre es mir man könnte angeben das die Bean XYZ genau das Message-Bundle "messages_anwendung2" verwenden soll und die Bean ABC eben das Message-Bundle "messages_anwendung1".



Da Du die Fehlerbehandlung auf Beanseite (und nicht auf der JSP-View Seite) machen willst verstehe ich nicht wieso Du application/local config in faces-config nutzt. Dies benutzt man normal nur, um auf der JSP Seite auf Bundle zugreifen zu können. Auf der Beanseite müsstest Du zB so vorgehen:


```
public void validateUserName(FacesContext context,
			 UIComponent componentToValidate,
			 Object value) 
			 throws ValidatorException {
				
		// if getUserByName != null the username exists
		if (UserRegistry.getUserByName((String)value.toString()) != null) {
			FacesMessage message = new FacesMessage(this.getMessageBundle().
													getString("RegisterBean.userExists"));
			throw new ValidatorException(message);
		}		
	}
```
Wobei das messageBundle wie in dem EE 5 Link von oben definiert ist.

Falls du JSF 1.2 nutzt könntest Du jedoch zb. mit requiredMessage für die Fehlermeldung im h:inputField arbeiten. 

Cu
Alex


----------



## Berndt (3. Jul 2007)

Hallo Alex,

ja ich arbeite mit JSF 1.2. Könntest du mir bitte zeigen wie das mit "requiredMessage" geht?

Also die Fehlerbearbeitung war auch bisher in der JSP-View, hatte die Eingabefelder mit "required" belegt gehabt. Allerdings haben die vielen verschiedenen Message-Bundles die Fehlermeldungen überschrieben gehabt. Um genau zu sein, das Message-Bundle was zuletzt eingelesen wird, dessen Fehlermeldungen sind gültig und überschreiben die Fehlermeldungen der anderen Message-Bundles.

Wie oben schon erwähnt habe ich 3 Message-Bundles. Jedes Bundle hat eigene Texte zu 
javax.faces.component.UIInput.REQUIRED , da z.B. ein Onlineshop andere Fehlermeldungstexte anzeigen soll als eine normale Homepage.
Nur funktioniert das leider nicht, weshalb ich wohl der Meinung bin das ich die Fehlerbehandlung in die Bean verlagern muss, weil ich wohl nur dort angeben kann, woher JSF seine Fehlermeldung für 
javax.faces.component.UIInput.REQUIRED beziehen soll. Nur dort kann ich bisher angeben welches Message-Bundle benutzt werden soll. 
Ich hoffe es gibt eine Möglichkeit einer JSP-View zu sagen das es nur das Message-Bundle X benutzen soll für Fehlermeldungen. Dann könnte ich auf die Bean verzichten.


----------



## WeirdAl (3. Jul 2007)

Schau mal hier. anstatt required="true" benutzt du einfach requiredMessage="Bla blub". Dann ist required "an" sowie die Message "Bla blub" wird geworfen.

Cu
Alex


----------



## Berndt (3. Jul 2007)

Hm und woher bezieht JSF dann die Fehlermeldung, also aus welchem Message-Bundle?


----------



## WeirdAl (4. Jul 2007)

Mhh? Mit requiredMessage überschreibst Du explizit die in
javax.faces.component.UIInput.REQUIRED enthaltene Standardnachricht. Wenn Du ein eigenes messageBundle nutzen willst, dann definier ein SystemMessageBundle, da bei mehreren Bundles die von dir beschriebenen Probleme auftreten.(Die einzelnen Bundles überschreiben sich gegenseitig, da sie nacheinander initialisiert werden)

Cu
Alex


----------



## Berndt (4. Jul 2007)

Könntest du mir bitte sagen wie das mit dem "SystemMessageBundle" funktioniert? Ich glaube das ist die Lösung für mein Problem.

Danke!!


----------



## Berndt (4. Jul 2007)

So hab grad festgestellt das "requiredMessage" nicht mit MyFaces funktioniert sondern nur mit der JSF Referenzimplementierung. Leider benutze ich MyFaces


----------



## WeirdAl (4. Jul 2007)

Huhu,



> Könntest du mir bitte sagen wie das mit dem "SystemMessageBundle" funktioniert? Ich glaube das ist die Lösung für mein Problem.



Damit ist ein "normales" MessageBundle gemeint, dass die JSF Standardnachricht durch eigene custom-Nachrichten überschreibt. Hier ist ein Sun Tutorial das dir evtl hilft. Es ist zwar für den Java Studio Creator gedacht, jedoch ist die Übersicht der "Keys" von Bedeutung.
Im Prinzip hast du dies ja zu Beginn deiner Fragestellung schon gehabt. Da Du jedoch 3 Bundles angegeben hast und die 3 Bundles der Deklarationsreihenfolge nach initialisiert werden, haben sich die Bundle gegenseitig überschrieben.

Das requiredMessage mit den myFaces-Tags nicht funktionieren liegt dadran, dass myFaces zurzeit wohl nur JSF 1.1 unterstützt.

Wenn Du wirklich pro Formular eine extra required Nachricht benötigst und requiredMessage nicht nutzen kannst, wirst Du um einen eigenen Validator nicht herum kommen. 
Ich bin auch kein JSF Spezi, daher ist es sehr gut möglich, das es doch eine andere Lösung für dein Problem gibt . Versuchs mal im Sun Forum bzw. in der JavaRanch.

Cu
Alex


----------



## Berndt (5. Jul 2007)

Vielen Dank für deine ausführlichen Tipps. Werde wohl die Variante mit dem eigenen Validator ausprobieren.

Gibts dabei irgendwas zu beachten? Glaub das Feld "required=true" muss ich wohl weglassen beim h:inputtext ansonsten funktioniert mein eigener Validator nicht oder?


----------



## WeirdAl (5. Jul 2007)

Hi,
probiers einfach mal aus. Ich denke aber das required Tag solltest du in der Tat weglassen.

Cu
Alex


----------



## Berndt (5. Jul 2007)

Leider funktioniert es so nicht. Das System springt erst in die Validation-Methode rein, wenn man etwas eingegeben hat. Befindet sich also im inputfeld nichts drinnen wird die Methode gar nicht aufgerufen. Derselbe Effekt tritt auch bei Radio-Buttons auf. Wenn keiner ausgewählt ist, dann wird auch keine Validierungsmethode aufgerufen.

Code in der JSF-Datei:

```
<h:inputText id="lastname" validator="#{Mybean.validateInput}" value="#{Mybean.lastname}" />
```


Code in der Mybean.java

```
public void validateInput(FacesContext context, UIComponent componentToValidate, Object value) throws ValidatorException {
            System.out.println("********************* hat geklappt  **********");
...
}
```

Gibts eine Möglichkeit das die Validierungsmethode jedesmal aufgerufen wird, auch wenn keine Eingabe erfolgt ist?


----------

