I have a Problem with jsf and multiple languages. So my strings are in WEB_INF/classes/texte_<lang>.properties files. And are accessed for example like that
<h:outputLabel value="#{messages.err_text}"/>
which works fine.
The problem is, i have <h:outputLabel... element where i want to show an error message depending on the error. I would like something that works like this:
<h:outputLabel value="#{someBean.errMsg}/>
With a Bean like that
#ManagedBean()
#SessionScoped
public class SomeBean{
public String getErrMsg(){
if(something){
return "#{messages.err_text}"
}else if(somethingElse){
return "#{messages.err_text2}"
}else{
return "#{messages.err_text3}"
}
}
}
Just to be clear it doesn't work that way. I'm looking for a similar solution (or any solution) that works.
Thanks for reading.
Don't do it that way. The model shouldn't be aware of the view. Localization also doesn't strictly belong in the model. The model should instead prepare some state which the view has to be aware of.
One way would be:
public String getErrMsg(){
if (something) {
return "err_text";
} else if (somethingElse) {
return "err_text2";
} else {
return "err_text3";
}
}
<h:outputLabel value="#{messages[someBean.errMsg]}" />
Other way would be returning an enum as demonstrated in the following related questions: Localizing enum values in resource bundle and How to use enum values in f:selectItem(s).
The reason why what you have now is not working, is because the value attribute of the outputText is evaluated as a plain String, and not as an EL expression.
Going by what you are working with now, the best way to proceed is to inject the resource bundle directly into your bean:
#ManagedProperty("#{messages}")
ResourceBundle messages;
And then,
public String getErrMsg(){
if(something){
messages.getString("err_text");
}
}
In case you're not aware, traditionally, error messages are presented using the h:message component.
On an unrelated note to your original question, you should also know that it's not generally advisable to have processing logic buried in your getter. For one thing, the getter is called multiple times during the rendering of your page. Also for this to work properly, you should be able to guarantee that the value something will stay consistent across the entire lifecycle of a single JSF request
Related
I have a backend restservice call, returning a value, with which I have to execute a JS function (for simplicity, I took "alert" here, in the frontend. This has to be implemented in JSF, and I'm having a hard time.
And, this is the catch, for performance reasons, I want the backend rest-callto be executed on click.
Here is (amongst many other things), what I have tried:
<p:commandLink action="#{viewingSessionBean.prepareViewingSession(document)}" oncomplete="alert('#{viewingSessionBean.name(document)}')">
<p:graphicImage value="documentViewerPopup.png"/>
</p:commandLink>
Here the bean (shortended to make the point clearer):
#ManagedBean
#ViewScoped
public class ViewingSessionBean implements Serializable {
private String name;
public String prepareViewingSession(Document document) {
name = restClient.call()
hashMap.put(document.getBlobId(), name);
return null; // don't navigate away...
}
public String name(Document document) {
return hashMap.get(document.getBlobId()); // return null if nothing is cached for the document yet there
}
}
I'd like to do something like this (pseudo code... don't have h:commandScript..., too old JSF, no way to upgrade)
<h:commandScript action="alert('#{viewingSessionBean.prepareViewingSession(document)}') />
That's something a bit tricky to accomplish, but stil doable.
One thing you must have in mind first: The JavaScript code you write in a .xhtml is rendered in a 'static' way. But what means 'static'? It means that if you reference a bean variable inside of your JavaScript code, and then update this variable value inside your bean, your printed JavaScript code will not be able to see these changes you just made. In this case you must first update your JavaScript code (using ajax) to get the changes in your variable and only then execute it.
Let's start with your bean:
#ManagedBean
#ViewScoped
public class ViewingSessionBean implements Serializable {
private String variable;
public String getVariable() {
return this.variable;
}
public void updateVariableValue(Document document) {
variable = restClient.call();
}
}
Now, the .xhtml code:
<h:form id="form">
<p:commandLink id="firstLink"
actionListener="#{viewSessionBean.updateVariableValue(document)}"
update=":form:secondLink"
oncomplete="$('#form\\:secondLink').click()"/>
<p:commandLink id="secondLink" onclick="alert('#{viewSessionBean.variable}')" style="display: none;"/>
</h:form>
Note a few things:
First: It was used two commandLinks, and not only one, why? Because at the time of the oncomplete call of the first Link the bean variable is already up-to-date, but your html code is not. So in order to have the updated value of the bean variable we do the following things:
Call the actionListener to update the variable value on the bean;
Make an ajax update on the second Link to get the updated value from the bean;
Call the oncomplete method and call a click to the second Link (now updated with the correct values);
Second: To call the click on the second Link we must escape the two dots on the jQuery call.
Third: The second Link is set with the display: none style to make it invisible in the screen.
Now just some thoughts about it: JSF works pretty well alongside JavaScript, but sometimes we have to make some clumsy tricks like this one to accomplish an "easy" task. I'm not saying that JSF is bad, but I think we could have a more 'out-of-box' approach to these kind of things. Just my opinion though.
As for good user feedback, I am using messages on multiple sites in my webapplication.
To add a message, I simple use:
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(type, "", message));
I added variables for type and message, because it depends on different validation.
Well, I am using different ManagedBeans for different sites, this is just normal.
It came to my mind, what is the best practice for adding those messages in different ManagedBeans.
Currently, I am always using the above code snippet like over 30 times (and it will become more and more for sure).
Should I create a Bean with SessionScopedannotated or #ApplicationScoped? Do you have any other hints, that should I know?
Just hide away repeated static code into a reusable static method to make it more DRY ("Don't Repeat Yourself").
Design the static method in such way that you can ultimately refactor from this,
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(type, "", message));
to something like this,
Messages.addGlobalInfo(message);
or even with an import static com.example.Messages.*; (Eclipse: Ctrl+Shift+M the line):
addGlobalInfo(message);
It doesn't need to be a managed bean as it doesn't hold any state. Moreover, you should make the default constructor of such an utility class private, so Java/JSF can in first place already not construct it via new operator or Class#newInstance() in reflection. If you're using CDI, annotate it if necessary with #Typed with an empty value to prevent it from being registered as managed bean candidate via Bean<T>.
#Typed
public final class Messages {
private Messages() {}
// ...
}
JSF utility library OmniFaces has exactly this utility class: org.omnifaces.util.Messages.
May be just move this code to some utility class:
public void static addMessage(FacesMessage.Severity type, String message){
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(type, "", message));
}
Also you can create several methods with one argument: addInfoMessage, addErrorMessage, ...
The requirements of the application that I'm building demands that user roles are to be dynamic, they will be stored in the database, and they will also be mapped to functionalities (forms) of the application, also stored in the database.
Restricting a role from accessing a specific page won't be difficult, but the requirements also states that form inputs must be customized based on roles, which means, an input can be mandatory or not, visible or not, read-only or not based on the role.
My approach to control these restrictions is based on creating a property file for each role, which will store all the inputs of all the forms in the application, as keys, and a long string as value in which we define the state of the input, like the following:
user-inputs.properties
# form.input=mandatory:visibility
searchBooks.bookName=true:true
searchBooks.bookCategory=false:true
searchBooks.authorName=false:false
admin-inputs.properties
searchBooks.bookName=true:true
searchBooks.bookCategory=false:true
searchBooks.authorName=false:true
And then do some magic Java code, whenever a form is accessed, read its inputs properties from the file of the specific user role, and parse the values so I could provide the right value for the rendered="" and required="" attribute of an <h:inputText/>.
This could be a solution, but the inputs of the application are much more than a book name and category, means I will be putting lots of required and rendered attributes which will make JSF pages look ugly with huge amount of variables in the managed bean.
Is there a better approach/framework/solution to my issue?
I think that you are in the right way, and i will continue using your approach which consists of creating multiple property files, one for each user, except that we will not use a any "huge amount of variables
in the managed bean".
So, the first step consists on managing multiple resource properties using a single resource bundle prefix ( the <var></var> in <resource-bundle>), in the second step we will see how to switch between those files, and in the last step we will read from property file using JSTL.
Managing multiple property files:
We start by defining our ResourceBundle in the faces-config file:
<application>
<resource-bundle>
<base-name>UserMessages</base-name>
<var>msgs</var>
</resource-bundle>
</application>
UserMessages is a ResourceBundle where we will implement the logic that allow us to switch between our property files (assuming that yourpackage.user-inputs is the fully qualified name of your user-inputs.properties):
import java.util.Enumeration;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import javax.faces.context.FacesContext;
public class UserMessages extends ResourceBundle {
public UserMessages() {
// we are loading user-inputs.properties as the default properties file
setParent(getBundle("yourpackage.user-inputs", FacesContext.getCurrentInstance()
.getViewRoot().getLocale()));
}
#Override
protected Object handleGetObject(String key) {
// we could just return parent.getObject(key) but we want to respect JSF recommandations
try {
return parent.getObject(key);
} catch (MissingResourceException e) {
return "???" + key + "???";
}
}
#Override
public Enumeration<String> getKeys() {
return parent.getKeys();
}
// this is the method that will allow us to switch between our .properties
public void setResourceBundle(String basename) {
setParent(getBundle(basename, FacesContext.getCurrentInstance()
.getViewRoot().getLocale()));
}
}
Switching between property files:
In order to switch from a property file to another we will need to use the method setResourceBundle(String basename) that we just declared in our class above, So in the managed bean where you are declaring your business logic and where you are intending to switch files depending on the user's role, you need to inject the bundle, like:
//don't forget adding getters and setters or you end with NullPointerException
#ManagedProperty("#{msgs}")
private UserMessages userMesssages;
Then, to switch to another file (admin-inputs.properties), just use it like this:
//yourpackage.admin-inputs is the fully qualified name
userMesssages.setResourceBundle("yourpackage.admin-inputs");
NB: You can inject the bundle in that way (above) only in request scoped beans, to use it in broader scopes please see: Read i18n variables from properties file in a Bean
Now, as we can switch easily from the user-inputs to the admin-inputs, the last step is the easiest one.
Parsing the property file:
The bad news, is that when using this approach you will need to add rendered="" and required="" attribute to every input you are willing to manage (but don't forget that the good ones was that you will not need to manage variables in managed beans ;) ).
First, you need to add JSTL namespaces declaration on the top of your xhtml file:
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
you can find more about JSTL functions in the javadocs, regarding the function substringAfter:
Returns a subset of a string following a specific substring.
Example:
P.O. Box: ${fn:substringAfter(zip, "-")}
The function substringBefore:
Returns a subset of a string before a specific substring.
Example:
Zip (without P.O. Box): ${fn:substringBefore(zip, "-")}
Second, as the first part of your String represents the required attribute:
//Returns the substring of msgs['searchBooks.authorName'] before the first occurrence of the separator ':'
required="${fn:substringBefore(msgs['searchBooks.authorName'], ':')}"
and the second part:
//Returns the substring of msgs['searchBooks.authorName'] after the first occurrence of the separator ':'.
rendered="${fn:substringAfter(msgs['searchBooks.authorName'], ':')}"
See also:
JSF Internationalization f:loadbundle or through faces-config:
Performance point
Difference between by Application#getResourceBundle() and ResourceBundle#getBundle() in JSF 2.0
How to remove the surrounding ??? when message is not found in
bundle
Context Sensitive Resource Bundle entries in JavaServer Faces
applications – going beyond plain language, region & variant
locales
I would like to know the best practice for a class oriented DDD.
Since i am doing domain validation in custom setters named ChangeX(string x) i might be pushed to use this as property.
public virtual string example { get;
private set; }
However, that not very good since it disable me from using the object initialization feature such as :
new Object { Example = "Some example"
}
So i though why not passing the custom set into the property set ? like this
public virtual string Example { get {
return Example; } set {
ChangeExample(value); } }
Is this can lead to any problems ? it is against best practices ?
Thanks.
Real problem here is using setters as such. Why do You need them?
When You use setters, You lose isolation - You can modify state of objects from outside w/o them knowing that. That leads to procedural code.
In contrast - You should ask objects to do something (not just modify their state) that would eventually might lead to them changing their own state.
I think this solution is fine. One reason to have setters is to make sure your under laying fields never hold incorrect values.
If you have a class with some plain get/set properties, is there any reason to use the getters within the class methods, or should you just use the private member variables? I think there could be more of an argument over setters (validation logic?), but I'm wondering just about getters.
For example (in Java) - is there any reason to use option 2?:
public class Something
{
private int messageId;
public int getMessageId() { return this.messageId; }
public void setMessage(int messageId) { this.messageId = messageId; }
public void doSomething()
{
// Option 1:
doSomethingWithMessageId(messageId);
// Option 2:
doSomethingWithMessageId(getMessageId());
}
}
Java programmers in general tend to be very consistent about using getter methods. I program multiple languages and I'm not that consistent about it ;)
I'd say as long as you don't make a getter it's ok to use the raw variable - for private variables. When you make a getter, you should be using only that. When I make a getter for a private field, my IDE suggests that it replace raw field accesses for me automatically when I introduce a getter. Switching to using a getter is only a few keystrokes away (and without any chance of introducing errors), so I tend to delay it until I need it.
Of course, if you want to stuff like getter-injection, some types of proxying and subclassing framworks like hibernate, you have to user getters!
With getters you wont accidentally modify the variables :) Also, if you use both getters and the "raw" variable, your code can get confused.
Also, if you use inheritance and redefined the getter methods in child classes, getter-using methods will work properly, whereas those using the raw variables would not.
If you use the getter method everywhere - and in the future perform a code-search on all calls of getMessageId() you will find all of them, whereas if you had used the private ones, you may miss some.
Also if there's ever logic to be introduced in the setter method, you wont have to worry about changing more than 1 location for it.
If the value that you are assigning to the property is a known or verified value, you could safely use the private variable directly. (Except perhaps in some special situations, where it would be obvious why that would be bad.) Whether you do or not is more a matter of taste or style. It's not a performance issue either, as the getter or setter will be inlined by the compiler if it's simple enough.
If the value is unknown to the class, you should use the property to set it, so that you can protect the property from illegal values.
Here's an example (in C#):
public class Something {
private string _value;
public string Value {
get {
return _value;
}
set {
if (value == null) throw new ArgumentNullException();
_value = value;
}
}
public Something() {
// using a known value
_value = "undefined";
}
public Something(string initValue) {
// using an unknown value
Value = initValue;
}
}
If you use the getter you're ensuring you'll get the value after any logic/decisions have been applied to it. This probably isn't your typical situation but when it is, you'll thank yourself for this.
Unless I have a specific use case to use the internal field directly in the enclosing class, I've always felt that it's important to use access the field the same way it is accessed publicly. This ensures consistency in the return values across the board should there ever be any need to add some post-processing to the field via the getter method, or property. I feel like it's perfectly fine to access the raw field if you want its raw value for one reason or another.
More often than not, the getter encapsulation is plain and simple boilerplate code -- you're most likely not returning anything other than the field's value itself. However, in the case where you may want to change the way the data is presented at some point in the future, it's one less refactoring you have to make internally.