I implemented internationalization like in that tutorial!
When I change the language in my app. It works. But only until the next request happens. Then language settings are reset to my standard language -.-
What am I missing here:
LanguageBean.java
#ManagedBean(name="language")
#SessionScoped
public class LanguageBean implements Serializable{
private static final long serialVersionUID = 1L;
private String localeCode;
private static Map<String,Object> countries;
static{
countries = new LinkedHashMap<String,Object>();
countries.put("Deutsch", Locale.GERMAN); //label, value
countries.put("English", Locale.ENGLISH);
}
public Map<String, Object> getCountriesInMap() {
return countries;
}
public String getLocaleCode() {
return localeCode;
}
public void setLocaleCode(String localeCode) {
this.localeCode = localeCode;
}
//value change event listener
public void countryLocaleCodeChanged(ValueChangeEvent e){
String newLocaleValue = e.getNewValue().toString();
//loop country map to compare the locale code
for (Map.Entry<String, Object> entry : countries.entrySet()) {
if(entry.getValue().toString().equals(newLocaleValue)){
FacesContext.getCurrentInstance()
.getViewRoot().setLocale((Locale)entry.getValue());
}
}
}
}
my facelets template:
<h:selectOneMenu value="#{language.localeCode}" onchange="submit()"
valueChangeListener="#{language.countryLocaleCodeChanged}">
<f:selectItems value="#{language.countriesInMap}" />
</h:selectOneMenu>
faces-config:
<application>
<locale-config>
<default-locale>de</default-locale>
</locale-config>
<resource-bundle>
<base-name>org.dhbw.stg.wwi2008c.mopro.ui.text</base-name>
<var>msg</var>
</resource-bundle>
</application>
Add the following line to setLocaleCode().
FacesContext.getCurrentInstance().getViewRoot().setLocale(new Locale(localeCode));
See also this tutorial which I wrote.
Related
I am making a JSF project on eclipse neon using JSF 2.0, Primefaces and Bootsfaces components. Even though I am able to create the output and put it inside an arraylist, I am having hard time displaying that arraylist on datatable. Here is my Bean:
#ManagedBean
#SessionScoped
public class FinalList implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
List<ListElements> newList = new ArrayList<>();
public List<ListElements> getResultList(String url, String title) {
ListElements list = new ListElements();
list.setUrl(url);
list.setTitle(title);
newList.add(list);
return newList;
}
}
Here is the contents of my List:
public class ListElements implements Serializable {
private static final long serialVersionUID = 1L;
/**
*
*/
private String Title;
private String Url;
public String getTitle() {
return Title;
}
public void setTitle(String title) {
Title = title;
}
public String getUrl() {
return Url;
}
public void setUrl(String url) {
Url = url;
}
}
Here is my datatable on .xhtml page:
<h:form>
<b:dataTable id="datatbl" value="#{finalList.class}" var="d"
excel="true" csv="true" pdf="true" columnVisibility="true"
copy="true" print="true">
<b:dataTableColumn value="#{d.url}" />
<b:dataTableColumn value="#{d.title}" />
</b:dataTable>
</h:form>
Appearently I am not able to reach my ListElements list. If I try to change value="#{finalList.class}" with anything else , I get
list cannot be resolved as a member of finalList
error. I think I should be able to change it as value="#{finalList.list}". Can someone tell me where I go wrong?
I have tried every way I know but nothing changed. I desperately need help.
All help will be appreciated.
I try to use JSF in combination with Bean Validation. Basically, everything works well, the validation works as expected, I get the correct message, but there is an exception on my Glassfish console:
Warnung: EJB5184:A system exception occurred during an invocation on EJB MyEntityFacade, method: public void com.mycompany.testbv.AbstractFacade.create(java.lang.Object)
Warnung: javax.ejb.EJBException
at com.sun.ejb.containers.EJBContainerTransactionManager.processSystemException(EJBContainerTransactionManager.java:748)
....
....
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
at java.lang.Thread.run(Thread.java:744)
Caused by: javax.validation.ConstraintViolationException: Bean Validation constraint(s) violated while executing Automatic Bean Validation on callback event:'prePersist'. Please refer to embedded ConstraintViolations for details.
This exception occurs if I use custom constraints as well as predefined constraints.
Here is my sample code.
Sample Entity:
#Entity
#ValidEntity
public class MyEntity implements Serializable {
private static final long serialVersionUID = 3104398374500914142L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Size(min = 2)
private String name;
public MyEntity(String name) {
this.name = name;
}
public MyEntity() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Custom constraint:
#Constraint(validatedBy = MyValidator.class)
#Target({FIELD, METHOD, TYPE})
#Retention(RUNTIME)
public #interface ValidEntity {
String message() default "fail";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Custom validator:
public class MyValidator implements ConstraintValidator<ValidEntity, MyEntity>{
#Override
public void initialize(ValidEntity a) {
}
#Override
public boolean isValid(MyEntity t, ConstraintValidatorContext cvc) {
return false;
}
}
Sample Controller:
#Named
#SessionScoped
public class MyController implements Serializable {
private static final long serialVersionUID = -6739023629679382999L;
#Inject
MyEntityFacade myEntityFacade;
String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public void saveNewEntity() {
try {
myEntityFacade.create(new MyEntity(text));
} catch (Exception e) {
Throwable t = e;
while (t != null) {
if (t instanceof ConstraintViolationException) {
FacesContext context = FacesContext.getCurrentInstance();
Set<ConstraintViolation<?>> constraintViolations = ((ConstraintViolationException) t).getConstraintViolations();
for (ConstraintViolation<?> constraintViolation : constraintViolations) {
FacesMessage facesMessage = new FacesMessage(constraintViolation.getMessage());
facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR);
context.addMessage(null, facesMessage);
}
}
t = t.getCause();
}
}
}
}
Sample jsf page:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head></h:head>
<h:body>
<h:form>
<h:messages id="messages" />
<h:inputText value="#{myController.text}" />
<h:commandButton value="Save" action="#{myController.saveNewEntity()}" />
</h:form>
</h:body>
</html>
The MyEntityFacade only calls persist from entity manager.
As mentioned before, the application is running fine and the correct messages are shwon, but I want to avoid this exception in the Glassfish console.
Setting the validation mode in persistence.xml to NONE as discussed here is no option, because I want a validation.
I use JSF in version 2.2, the implementation is Mojarra. The version of Bean Validation is 1.1, the implementation is Hibernate Validator.
Application Server is Glassfish 4.0.
Class-level constraints do not work with JSF. Take a look at this answer. When you press the 'Save' button JSF checks only if name has at least 2 chars and does not take into account the ValidEntity constraint. JPA, on the other hand, complains that the bean is not valid and throws an exception.
UPDATE
1) the #Size constraint is on MyEntity.name property while in the facelet you have MyController.text property. In the JSF perspective there is nothing to validate. It has no knowledge of the MyEntity at all.
2) ValidEntity is always invalid, so JPA will always throw the exception (unless you disable validation) even if you properly set the MyEntity.name in the facelet.
I have the following problem!
On one of my sites i have a button:
<h:commandButton value="IDA Analyzer Results" action="#{SelectionBean.monitoringLog()}"/>
The method it calls with some part of the bean:
#ManagedBean(name = "SelectionBean")
#SessionScoped
public class TableSelectionBean {
private List<String> analyzerLog = new ArrayList<String>();
public String monitoringLog() throws FileNotFoundException, IOException{
String fileName = "/opt/IDA2/Linux/bin/"+"filtered_"+selectionMonitoringData.get(0).getMonitoringName()+"_result.txt";
if(selectionMonitoringData.get(0).getIsExecuted())
{
BufferedReader br = new BufferedReader(new FileReader(fileName));
try {
String line;
while ((line=br.readLine()) != null) {
getAnalyzerLog().add(line);
}
} finally {
br.close();
System.out.println(getAnalyzerLog());
}
}
return "analyzerresult.xhtml";
}
After i click this button as you can see it navigates me to an other page:
<h:body>
<h:form>
<h:commandButton value="hi" action="#{AnalyzerBean.myMethod()}"></h:commandButton>
</h:form>
</h:body>
Here is the Bean:
#ManagedBean(name = "AnalyzerBean")
#SessionScoped
public class AnalyzerResultBean {
#ManagedProperty(value="#{SelectionBean.analyzerLog}")
private List<String> analyzerLog;
public void myMethod(){
System.out.print(analyzerLog);
}
/**
* #return the analyzerLog
*/
public List<String> getAnalyzerLog() {
return analyzerLog;
}
/**
* #param analyzerLog the analyzerLog to set
*/
public void setAnalyzerLog(List<String> analyzerLog) {
this.analyzerLog = analyzerLog;
}
So when I'm trying to use this Managed property it says:
The scope of the object referenced by expression #{SelectionBean.analyzerLog}, view, is shorter than the referring managed beans (AnalyzerBean) scope of session but as you can see both of the is Session Scoped. What could be the problem?
If you use JSF 2.x and you want to navigate analyzerresult.xhtml page return analyzerresult
public String monitoringLog() throws FileNotFoundException, IOException{
return "analyzerresult";
}
.xhtml extension is not needed.
I want to add Liferay's CKEditor to my JSF portlet. I tried to find a way to add the CKEditor in JSF, but all the examples/solutions show how to add the CKEditor in a JSP not JSF.
I am using Liferay Portal 6.0 EE.
You can add the CKEditor to a JSF page by including the Liferay Faces Portal jar* in your project, and writing code similar to one of the following examples:
Liferay 6.2+ Example:
<portal:inputRichText value="#{backing.value}" />
Check out the Liferay Faces Showcase for live examples and more details.
Deprecated Liferay 6.2 and 6.1 Example:
<liferay-ui:input-editor editorImpl="editor.wysiwyg.default" value="#{backing.value}">
Deprecated Liferay 6.0 EE Example:
<liferay-ui:input-editor editorImpl="ckeditor" value="#{backing.value}">
*Since you are using Liferay 6.0 EE, you need to use LF Portal version 3.0.5-ga6. Consult the the Liferay Faces Version Scheme for more information on compatible Liferay Faces and Liferay Portal versions.
Use the below code. Reference Liferay Faces Showcase
inputRichText.xhtml
<alloy:outputStylesheet library="css" name="input-rich-text.css" />
<alloy:form id="exampleForm">
<alloy:field id="commentsField" label="#{i18n['comments']}" styleClass="input-rich-text-field">
<alloy:message id="commentsMessage" for="comments" />
</alloy:field>
<!-- Note: In this example, portal:inputRichText is intentionally not a child of alloy:field in order -->
<!-- to prevent it from being unnecessarily reinitialized when the alloy:field is re-rendered via Ajax. -->
<portal:inputRichText id="comments" label="#{i18n['comments']}"
required="#{showcaseModelBean.selectedComponent.required}"
value="#{inputRichTextBacking.applicant.comments}" />
<alloy:commandButton actionListener="#{inputRichTextBacking.submit}"
render=":exampleForm:commentsField :modelValue" value="#{i18n['submit']}" />
</alloy:form>
<alloy:outputText id="modelValue" value="#{inputRichTextBacking.applicant.comments}" />
InputRichTextBacking.java
#ManagedBean
#RequestScoped
public class InputRichTextBacking {
private static final Logger logger = LoggerFactory.getLogger(InputRichTextBacking.class);
private Applicant applicant;
private boolean resizable = true;
#PostConstruct
public void init() {
applicant = new Applicant();
if (ViewParamUtil.getUsage().equals("default-value")) {
applicant.setComments(
"<p>This is some <strong>bold</strong> text\nand this is some <em>italic</em> text.</p>");
}
}
public void submit() {
logger.info("You entered comments: " + applicant.getComments());
}
public void valueChangeListener(ValueChangeEvent valueChangeEvent) {
FacesContext facesContext = FacesContext.getCurrentInstance();
PhaseId phaseId = facesContext.getCurrentPhaseId();
logger.debug("valueChangeListener: phaseId=[{0}]", phaseId.toString());
String phaseName = phaseId.getName();
FacesMessage facesMessage = new FacesMessage("The valueChangeListener method was called during the " +
phaseName + " phase of the JSF lifecycle.");
facesContext.addMessage(null, facesMessage);
}
public Applicant getApplicant() {
return applicant;
}
public boolean isResizable() {
return resizable;
}
public void setResizable(boolean resizable) {
this.resizable = resizable;
}
}
Applicant.java
public class Applicant implements Serializable {
private static final long serialVersionUID = 4661552363081858711L;
private String city;
private String comments;
private Date dateOfBirth;
private String emailAddress;
private String firstName;
private String lastName;
private String phoneNumber;
private String postalCode;
private Long provinceId;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPostalCode() {
return postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public Long getProvinceId() {
return provinceId;
}
public void setProvinceId(Long provinceId) {
this.provinceId = provinceId;
}
}
input-rich-text.css
/* The Liferay Portal margin-bottom is 30px for div elements with class="control-group" (such as alloy:field). */
/* Set the margin-bottom to zero since the portal:inputRichText is not a child of the alloy:field component tag. */
.aui div.input-rich-text-field.control-group {
margin-bottom: 0px;
}
.aui div.portal-input-rich-text {
margin-bottom: 30px;
}
input-rich-text.properties
#
# The default key used by the editorImpl attribute is found in the Liferay portal.properties file:
#
# editor.wysiwyg.default=ckeditor
#
# For more information, see:
#
# https://github.com/liferay/liferay-portal/blob/6.2.1-ga2/portal-impl/src/portal.properties#L5282
#
# Alternate keys for BBCode and Creole can be specified in a custom portal-ext.properties file.
#
# For example:
#
com.liferay.faces.demos.showcase.ckeditor=ckeditor
com.liferay.faces.demos.showcase.ckeditor_bbcode=ckeditor_bbcode
com.liferay.faces.demos.showcase.ckeditor_creole=ckeditor_creole
You can use:
<aui:fieldset>
<script type="text/javascript">
function <portlet:namespace />initEditor() {
}
</script>
<aui:field-wrapper label="content">
<liferay-ui:input-editor width="100%" />
<aui:input name="content" type="hidden" />
</aui:field-wrapper>
</aui:fieldset>
Using <resource-bundle> files I'm able to have i18n text in my JSF pages.
But is it possible to access these same properties in my managed bean so I can set faces messages with i18n values?
Assuming that you've configured it as follows:
<resource-bundle>
<base-name>com.example.i18n.text</base-name>
<var>text</var>
</resource-bundle>
If your bean is request scoped, you can just inject the <resource-bundle> as #ManagedProperty by its <var>:
#ManagedProperty("#{text}")
private ResourceBundle text;
public void someAction() {
String someKey = text.getString("some.key");
// ...
}
Or if you just need some specific key:
#ManagedProperty("#{text['some.key']}")
private String someKey;
public void someAction() {
// ...
}
If your bean is however in a broader scope, then evaluate #{text} programmatically in method local scope:
public void someAction() {
FacesContext context = FacesContext.getCurrentInstance();
ResourceBundle text = context.getApplication().evaluateExpressionGet(context, "#{text}", ResourceBundle.class);
String someKey = text.getString("some.key");
// ...
}
Or if you only need some specific key:
public void someAction() {
FacesContext context = FacesContext.getCurrentInstance();
String someKey = context.getApplication().evaluateExpressionGet(context, "#{text['some.key']}", String.class);
// ...
}
You can even just get it by the standard ResourceBundle API the same way as JSF itself is already doing under the covers, you'd only need to repeat the base name in code:
public void someAction() {
FacesContext context = FacesContext.getCurrentInstance();
ResourceBundle text = ResourceBundle.getBundle("com.example.i18n.text", context.getViewRoot().getLocale());
String someKey = text.getString("some.key");
// ...
}
Or if you're managing beans by CDI instead of JSF, then you can create a #Producer for that:
public class BundleProducer {
#Produces
public PropertyResourceBundle getBundle() {
FacesContext context = FacesContext.getCurrentInstance();
return context.getApplication().evaluateExpressionGet(context, "#{text}", PropertyResourceBundle.class);
}
}
And inject it as below:
#Inject
private PropertyResourceBundle text;
Alternatively, if you're using the Messages class of the JSF utility library OmniFaces, then you can just set its resolver once to let all Message methods utilize the bundle.
Messages.setResolver(new Messages.Resolver() {
public String getMessage(String message, Object... params) {
ResourceBundle bundle = ResourceBundle.getBundle("com.example.i18n.text", Faces.getLocale());
if (bundle.containsKey(message)) {
message = bundle.getString(message);
}
return MessageFormat.format(message, params);
}
});
See also the example in the javadoc and the showcase page.
Another possibility:
faces-config.xml
<?xml version='1.0' encoding='UTF-8'?>
<faces-config ...>
<application>
<locale-config>
<default-locale>de</default-locale>
</locale-config>
<resource-bundle>
<base-name>de.fhb.resources.text.backend</base-name>
<var>backendText</var>
</resource-bundle>
</application>
</faces-config>
YourBean.java
FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
ResourceBundle backendText = app.getResourceBundle(context, "backendText");
backendText.getString("your.property.key");
Here is a solution I'm using, not as simple but at least working :
First class :
package com.spectotechnologies.website.util;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
/**
*
* #author Alexandre Lavoie
*/
public class MessageInterpolator extends ResourceBundleMessageInterpolator
{
public static final String LANGUAGE_TAG_PATTERN = "\\{[^}]*\\}";
#Override
public String interpolate(String p_sMessage, Context p_oContext)
{
return super.interpolate(replaceMessages(p_sMessage),p_oContext);
}
#Override
public String interpolate(String p_sMessage, Context p_oContext, Locale p_oLocale)
{
StringManager.setLocale(p_oLocale);
return super.interpolate(replaceMessages(p_sMessage),p_oContext,p_oLocale);
}
private String replaceMessages(String p_sMessage)
{
Matcher oMatcher;
String sKey;
String sReplacement;
StringBuffer sbTemp = new StringBuffer();
oMatcher = Pattern.compile(LANGUAGE_TAG_PATTERN).matcher(p_sMessage);
while(oMatcher.find())
{
sKey = oMatcher.group().substring(1,oMatcher.group().length() - 1);
sReplacement = StringManager.getString(sKey);
if(!sReplacement.startsWith("???"))
{
oMatcher.appendReplacement(sbTemp,sReplacement);
}
}
oMatcher.appendTail(sbTemp);
return sbTemp.toString();
}
}
Second class :
package com.spectotechnologies.website.util;
import com.spectotechnologies.util.BundleManager;
import com.spectotechnologies.util.FacesSessionManager;
import java.util.Locale;
/**
* set-up and interface a BundleManager
* save the bundleManager into the session
* #author Charles Montigny
*/
public final class StringManager
{
/** the session name of this class bundle manager */
public static final String BUNDLE_MANAGER_SESSION_NAME = "StringManager_BundleManager";
/** List of ResourceBundle names to load.
* Will be load in order.
* The last ones values may overrite the first ones values. */
private final static String[] BUNDLE_LIST = {
"com.spectotechnologies.hibernate.validation.resources.ValidationMessages",
"com.spectotechnologies.website.general.resources.ValidationMessages",
"com.spectotechnologies.website.general.resources.General"};
/** bundle manager */
private static BundleManager m_oBundleManager = null;
private static BundleManager getBundleManager()
{
if(m_oBundleManager == null)
{
// get the bundle into the session
m_oBundleManager = (BundleManager)FacesSessionManager.getObject(BUNDLE_MANAGER_SESSION_NAME);
if(m_oBundleManager == null)
{
// session was empty, load a new one
m_oBundleManager = new BundleManager();
for(int iIndex = 0; iIndex < BUNDLE_LIST.length; iIndex++)
{
m_oBundleManager.addBundle(BUNDLE_LIST[iIndex]);
}
// add the bundle to the session
FacesSessionManager.setObject(BUNDLE_MANAGER_SESSION_NAME, m_oBundleManager);
}
}
return m_oBundleManager;
}
/**
* get a string value in the bundle manager by a string key
* #param p_sKey the string key
* #return the value of the string key
*/
public static String getString(String p_sKey)
{
return getBundleManager().getStringValue(p_sKey);
}
/**
* set the locale
* #param p_oLocale the locale to set
*/
public static void setLocale(Locale p_oLocale)
{
getBundleManager().setLocale(p_oLocale);
// update the session
FacesSessionManager.setObject(BUNDLE_MANAGER_SESSION_NAME,
getBundleManager());
}
}
After you need to override BUNDLE_LIST with your properties files. Once done, use it like that :
sMessage = StringManager.getString("website.validation.modifySystem.modified");
If you have questions, do not hesitate!
EDIT :
You also need to declare the MessageInterpolator
META-INF/validation.xml
<validation-config
xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration">
<message-interpolator>com.spectotechnologies.website.util.MessageInterpolator</message-interpolator>
</validation-config>