I want to access the resource map, not from my CCS file as in
background-image: url("#{resource['primefaces-supertheme:images/ui-icons_ffffff_0.png']}");
but from my bean. Is it possible with EL evaluation only?
The true Java variant would be Application#createResrouce() and then Resource#getRequestPath():
FacesContext context = FacesContext.getCurrentInstance();
Resource resource = context.getApplication().getResourceHandler().createResource("images/ui-icons_ffffff_0.png", "primefaces-supertheme");
String url = resource.getRequestPath();
// ...
Note that you could just evaluate EL programmatically. You can use Application#evaluateExpressionGet() for this.
FacesContext context = FacesContext.getCurrentInstance();
String url = context.getApplication().evaluateExpressionGet(context, "#{resource['primefaces-supertheme:images/ui-icons_ffffff_0.png']}", String.class);
// ...
If you happen to use JSF utility library OmniFaces, this can be simplified via Faces utility class as:
String url = Faces.evaluateExpressionGet("#{resource['primefaces-supertheme:images/ui-icons_ffffff_0.png']}");
// ...
Related
I would like to be able to retrieve a string from a message bundle from inside a JSF 2 managed bean. This would be done in situations where the string is used as the summary or details parameter in a FacesMessage or as the message in a thrown exception.
I want to make sure that the managed bean loads the correct message bundle for the user's locale. It is not clear to me how to do this from a managed bean using JSF API calls.
My configuration is:
Using Tomcat 7 as the container so the solution cannot depend on API calls that only work in a full application server container
Using the JSF 2 reference implementation (Mojarra)
NOT using any libraries that allow CDI
NOTE: I did see this similar question, but it depends on features that are unavailable in my configuration
EDIT: I made a mistake in my original question. What I meant to ask was "How can I get a resource bundle string from inside a managed bean"? BalusC gave me the correct answer for what I asked. The solution for what I actually meant to ask is very similar:
public static String getResourceBundleString(
String resourceBundleName,
String resourceBundleKey)
throws MissingResourceException {
FacesContext facesContext = FacesContext.getCurrentInstance();
ResourceBundle bundle =
facesContext.getApplication().getResourceBundle(
facesContext, resourceBundleName);
return bundle.getString(resourceBundleKey);
}
Also, here is a link to another question that explains the difference between "message" bundles and "resource" bundles.
You can get the full qualified bundle name of <message-bundle> by Application#getMessageBundle(). You can get the current locale by UIViewRoot#getLocale(). You can get a ResourceBundle out of a full qualified bundle
name and the locale by ResourceBundle#getBundle().
So, summarized:
FacesContext facesContext = FacesContext.getCurrentInstance();
String messageBundleName = facesContext.getApplication().getMessageBundle();
Locale locale = facesContext.getViewRoot().getLocale();
ResourceBundle bundle = ResourceBundle.getBundle(messageBundleName, locale);
// ...
Update: as per the mistake in the question, you actually want to get the bundle which is identified by the <base-name> of <resource-bundle>. This is unfortunately not directly available by a standard JSF API. You've either to hardcode the same base name in the code and substitute the messageBundleName in the above example with it, or to inject it as a managed property on <var> in a request scoped bean:
#ManagedProperty("#{msg}")
private ResourceBundle bundle; // +setter
FacesContext context = FacesContext.getCurrentInstance();
ResourceBundle bundle = context.getApplication().getResourceBundle(context, "msg");
String message = bundle.getString("key");
here is key is property name which you want to access from properties file .
message = This is "message"
This entry is from messages.properites file. and "message" is "key" .
There are two ways to get String resource bundle in managed bean, using baseName or varName (see definition of each one below):
Using varName:
varName: is the String representing the <var></var> in <resource-bundle>
FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
ResourceBundle bundle = app.getResourceBundle(context, varName);
String msg = bundle.getString("key");
Using baseName:
baseName: The fully qualified name of the resource bundle (<base-name> in <resource-bundle>).
FacesContext context = FacesContext.getCurrentInstance();
Locale locale = context .getViewRoot().getLocale();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, loader);
String msg = bundle.getString("key");
In a JSF backing bean (Managed Bean, Weld Bean, doesn't matter), I can get the context path the client is on by calling
FacesContext ctx = FacesContext.getCurrentInstance();
String path = ctx.getExternalContext().getRequestContextPath();
This gives me the path the client currently accesses, like /myapplication.
Is it also possible to get the current page, like /home.faces, and how?
You normally want to use UIViewRoot#getViewId() for this.
String viewId = facesContext.getViewRoot().getViewId();
This is in EL also available as follows:
#{view.viewId}
Exactly this value is reuseable in navigation case outcomes such as <h:link outcome> and <h:button outcome>.
Alternatively, you can also use HttpServletRequest#getRequestURI() to get whatever the enduser is actually seeing in the browser address bar.
String uri = ((HttpServletRequest) externalContext.getRequest()).getRequestURI();
Which is in EL also available as follows:
#{request.requestURI}
Exactly this value is reuseable in <h:outputLink value> or plain <a href>. Note that you can't use it as navigation case outcome.
Ok, got it, it's
FacesContext ctx = FacesContext.getCurrentInstance();
HttpServletRequest servletRequest = (HttpServletRequest) ctx.getExternalContext().getRequest();
// returns something like "/myapplication/home.faces"
String fullURI = servletRequest.getRequestURI();
String uri = ((HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest()).getRequestURI();
String str = ((HttpServletRequest) FacesContext.getCurrentInstance()
.getExternalContext().getRequest()).getRequestURI();
System.out.println(str);
I have a dynamically generated Datatable, like this
DataTable dataTable = new DataTable();
dataTable.setValue(relatorioVOList);
dataTable.setVar("rVO");
Column checkBoxColumn = new Column();
checkBoxColumn.getChildren().add(this.viewComponentBuilder.createExpressionTextWithLink("#{rVO.iRelatorio}","#{rVO.nNome}"));
dataTable.getColumns().add(checkBoxColumn);
public HtmlForm createExpressionTextWithLink(String iRelatorioExpressionValue, String valueExpressionValue) {
HtmlForm form = new HtmlForm();
HtmlCommandLink link = new HtmlCommandLink();
//config
FacesContext context = FacesContext.getCurrentInstance();
Application application = context.getApplication();
ExpressionFactory ef = application.getExpressionFactory();
ELContext elc = context.getELContext();
//value that is the reports name
ValueExpression nameValueExp = ef.createValueExpression(elc, valueExpressionValue, Object.class);
link.setValueExpression("value", nameValueExp);
//action that goes to method teste when link is clicked
MethodExpression methodExpression = createMethodExpression("#{componenteC.teste(rVO.iRelatorio)}", String.class, Integer.class);
link.setActionExpression(methodExpression);
form.getChildren().add(link);
return form;
}
private static MethodExpression createMethodExpression(String expression, Class<?> returnType, Class<?>... parameterTypes) {
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext.getApplication().getExpressionFactory().createMethodExpression(
facesContext.getELContext(), expression, returnType, parameterTypes);
}
In ComponenteC, a RequestScopedBean, the teste function
public String teste(Integer iRelatorio) {
System.out.println("cheguei");
return "componente";
}
The goal is that the teste function will generate an url according to the iRelatorio parameter.
The issue here is that the function is never called. I tried replacing the rVO.iRelatorio with an explicit 10, "#{componenteC.teste(10)}" and even then the action seems to not be fired.
The report name is displayed correctly.
Dynamically created UIInput, UICommand and UINamingContainer components must have a fixed id assigned. Otherwise it will get an autogenerated one which is not necessarily the same when the view is restored. The component ID is used in request parameter names in submitted form data, which JSF would then use to collect the submitted input values and identify the invoked commands during apply request values phase. If the component ID changes, then JSF won't be able to perform the apply request values phase as intented.
Thus, act accordingly:
dataTable.setId("tableId");
// ...
form.setId("formId");
// ...
link.setId("linkId");
There are other potential causes, but they are not visible in the information provided so far in the question. To cover that, take your time to carefully read the following related answers on "dynamically" creating components/views:
Create inputtext dynamically
How does the 'binding' attribute work in JSF? When and how should it be used?
How to create dynamic JSF form fields
That said, you're really better off using XHTML to declare and create components instead of all that Java code mess. XHTML(+XML) is much more declarative and readable and therefore better understandable and maintainable. JSTL may be very helpful in this all.
Following java code allows to access any object or variable from faces context:
ELContext elCtx = facesContext.getELContext();
ExpressionFactory exprFac = facesContext.getApplication().getExpressionFactory();
MyProperty myProperty = (MyProperty) exprFac.createValueExpression(elCtx, "#{somebean.someattr.someproperty}", MyProperty.class).getValue(elCtx);
I use the code from within my custom converter to read additional converting parameters from context.
The code works correctly if #{somebean} is defined as normal backing bean within JSF context.
Facelets allow to create 'shortcut' to JSF expressions. Example:
<ui:param name="shortcut" value="#{somebean.someattr.someproperty}" />
<div>#{somebean.someattr.someproperty} equals #{shortcut}</div>
In this case both #{somebean.someattr.someproperty} and #{shortcut} have the same value.
However these 'shortcut' names are not accessible using java code above. For example:
MyProperty myProperty1 = (MyProperty) exprFac.createValueExpression(elCtx, "#{somebean.someattr.someproperty}", MyProperty.class).getValue(elCtx);
// myProperty1 has expected value
MyProperty myProperty2 = (MyProperty) exprFac.createValueExpression(elCtx, "#{shortcut}", MyProperty.class).getValue(elCtx);
// myProperty2 is null
Is there a way to access a facelets context and to read 'shortcut' parameter values, defined on the current JSF page?
I had the same problem and have chosen the following approach:
/**
* Führt eine Expression im aktuellen Faces EL Context
* UND im Facelets El Context aus.
*
* #param facesContext
* #param expression
* #return object
*/
private static Object executeExpressionInUIContext (final FacesContext facesContext, final String expression) {
final ELContext elContext = facesContext.getELContext();
final Application application = facesContext.getApplication();
Object result = executeExpressionInElContext(application, elContext, expression);
if (null == result) {
FaceletContext faceletElContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
result = executeExpressionInElContext(application, faceletElContext, expression);
}
return result;
}
private static Object executeExpressionInElContext (Application application, ELContext elContext, String expression) {
ExpressionFactory expressionFactory = application.getExpressionFactory();
ValueExpression exp = expressionFactory.createValueExpression(elContext, expression, Object.class);
return exp.getValue(elContext);
}
"ui:param" is part of the Facelet view handling technology. Facelets extends JSF.
Both technologies use their own Context when storing variables.
Beside the Faces El Context there is a Facelet El Context (FaceletContext).
The stated method evaluates expressions in both contexts. Be aware that this will not work if two values are stored under the same name in each context.
It seems that facelet shortcuts do not exist in the context, where I try to access them.
I have made following workaround: On JSF page where my input element is placed, I have added a <f:param> element as child of the input with my converter.
<h:inputText id="myid" value="#{action.myinput}">
<f:converter converterId="myConverter" />
<f:param name="converterParameters" shortcut="#{somebean.someattr.someproperty}"/>
</h:inputText>
Then in converter I'm able to find UIParam element as one of the input children and read my shortcuts from it.
public Object getAsObject(FacesContext context, UIComponent component, String value) {
MyProperty myProperty = null;
try {
for (final UIComponent child : component.getChildren()) {
if ("converterParameters".equals(child.getAttributes().get("name"))) {
final ELContext elCtx = context.getELContext();
myProperty = (MyProperty) child.getValueExpression("shortcut").getValue(elCtx);
break;
}
}
if (myProperty == null) {
throw new NullPointerException("My property is undefined.");
}
} catch (Exception e) {
LOG.error("Cannot convert " + value + ". Use <f:param name=\"converterParameters\" "
+ "shortcut=\"#{here.comes.shortcut}\"/> for your input element. ", e);
throw new ConverterException("Cannot initialize converter.", e);
}
//...
}
The mapping of ui:param is not stored in context, it's in the VariableMapper of each individual ValueExpression.
So if you need to create ValueExpression programmatically, relying on another ValueExpression's varMapper, you can do something like this:
VariableMapper varMapper = new DefaultVariableMapper();
varMapper.setVariable(mappingName, component.getValueExpression(mappedAttributeName));
return new ValueExpressionImpl(expression, null, null, varMapper, expectedType);
I would like to be able to retrieve a string from a message bundle from inside a JSF 2 managed bean. This would be done in situations where the string is used as the summary or details parameter in a FacesMessage or as the message in a thrown exception.
I want to make sure that the managed bean loads the correct message bundle for the user's locale. It is not clear to me how to do this from a managed bean using JSF API calls.
My configuration is:
Using Tomcat 7 as the container so the solution cannot depend on API calls that only work in a full application server container
Using the JSF 2 reference implementation (Mojarra)
NOT using any libraries that allow CDI
NOTE: I did see this similar question, but it depends on features that are unavailable in my configuration
EDIT: I made a mistake in my original question. What I meant to ask was "How can I get a resource bundle string from inside a managed bean"? BalusC gave me the correct answer for what I asked. The solution for what I actually meant to ask is very similar:
public static String getResourceBundleString(
String resourceBundleName,
String resourceBundleKey)
throws MissingResourceException {
FacesContext facesContext = FacesContext.getCurrentInstance();
ResourceBundle bundle =
facesContext.getApplication().getResourceBundle(
facesContext, resourceBundleName);
return bundle.getString(resourceBundleKey);
}
Also, here is a link to another question that explains the difference between "message" bundles and "resource" bundles.
You can get the full qualified bundle name of <message-bundle> by Application#getMessageBundle(). You can get the current locale by UIViewRoot#getLocale(). You can get a ResourceBundle out of a full qualified bundle
name and the locale by ResourceBundle#getBundle().
So, summarized:
FacesContext facesContext = FacesContext.getCurrentInstance();
String messageBundleName = facesContext.getApplication().getMessageBundle();
Locale locale = facesContext.getViewRoot().getLocale();
ResourceBundle bundle = ResourceBundle.getBundle(messageBundleName, locale);
// ...
Update: as per the mistake in the question, you actually want to get the bundle which is identified by the <base-name> of <resource-bundle>. This is unfortunately not directly available by a standard JSF API. You've either to hardcode the same base name in the code and substitute the messageBundleName in the above example with it, or to inject it as a managed property on <var> in a request scoped bean:
#ManagedProperty("#{msg}")
private ResourceBundle bundle; // +setter
FacesContext context = FacesContext.getCurrentInstance();
ResourceBundle bundle = context.getApplication().getResourceBundle(context, "msg");
String message = bundle.getString("key");
here is key is property name which you want to access from properties file .
message = This is "message"
This entry is from messages.properites file. and "message" is "key" .
There are two ways to get String resource bundle in managed bean, using baseName or varName (see definition of each one below):
Using varName:
varName: is the String representing the <var></var> in <resource-bundle>
FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
ResourceBundle bundle = app.getResourceBundle(context, varName);
String msg = bundle.getString("key");
Using baseName:
baseName: The fully qualified name of the resource bundle (<base-name> in <resource-bundle>).
FacesContext context = FacesContext.getCurrentInstance();
Locale locale = context .getViewRoot().getLocale();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, loader);
String msg = bundle.getString("key");