Show image from string path outside the project Primefaces [duplicate] - image

I'm trying to display image bytes which is saved in database as a StreamedContent in the <p:graphicImage> as follows:
<p:graphicImage value="#{item.imageF}" width="50" id="grpImage" height="80"/>
private StreamedContent content; // getter and setter
public StreamedContent getImageF() {
if (student.getImage() != null) {
InputStream is = new ByteArrayInputStream(student.getImage());
System.out.println("Byte :"+student.getImage());
content = new DefaultStreamedContent(is, "", student.getStuID());
System.out.println("ddd ------------------------------- " + content);
return content;
}
return content;
}
This returns a blank image. How is this caused and how can I solve it?
The stdout prints the following:
INFO: Byte :[B#a2fb48
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent#b0887b
INFO: Byte :[B#a2fb48
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent#1d06a92
INFO: Byte :[B#d52f0b
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent#39a60
INFO: Byte :[B#d52f0b
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent#8c3daa
INFO: Byte :[B#124728a
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent#1dbe05b
INFO: Byte :[B#124728a
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent#66a266
INFO: Byte :[B#a2fb48
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent#1293976
INFO: Byte :[B#a2fb48
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent#17b7399
INFO: Byte :[B#d52f0b
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent#1e245a5
INFO: Byte :[B#d52f0b
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent#4a7153
INFO: Byte :[B#124728a
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent#1561bfd
INFO: Byte :[B#124728a
INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent#47a8c2

The <p:graphicImage> requires a special getter method. It will namely be invoked twice per generated image, each in a completely different HTTP request.
The first HTTP request, which has requested the HTML result of a JSF page, will invoke the getter for the first time in order to generate the HTML <img> element with the right unique and auto-generated URL in the src attribute which contains information about which bean and getter exactly should be invoked whenever the webbrowser is about to request the image. Note that the getter does at this moment not need to return the image's contents. It would not be used in any way as that's not how HTML works (images are not "inlined" in HTML output, but they are instead requested separately).
Once the webbrowser retrieves the HTML result as HTTP response, it will parse the HTML source in order to present the result visually to the enduser. Once the webbrowser encounters an <img> element during parsing the HTML source, then it will send a brand new HTTP request on the URL as specified in its src attribute in order to download the content of that image and embed it in the visual presentation. This will invoke the getter method for the second time which in turn should return the actual image content.
In your particular case PrimeFaces was apparently either unable to identify and invoke the getter in order to retrieve the actual image content, or the getter didn't return the expected image content. The usage of #{item} variable name and the lot of calls in the log suggests that you were using it in an <ui:repeat> or a <h:dataTable>. Most likely the backing bean is request scoped and the datamodel isn't properly preserved during the request for the image and JSF won't be able to invoke the getter during the right iteration round. A view scoped bean would also not work as the JSF view state is nowhere available when the browser actually requests the image.
To solve this problem, your best bet is to rewrite the getter method as such so that it can be invoked on a per-request basis wherein you pass the unique image identifier as a <f:param> instead of relying on some backing bean properties which may go "out of sync" during subsequent HTTP requests. It would make completely sense to use a separate application scoped managed bean for this which doesn't have any state. Moreover, an InputStream can be read only once, not multiple times.
In other words: never declare StreamedContent nor any InputStream or even UploadedFile as a bean property; only create it brand-new in the getter of a stateless #ApplicationScoped bean when the webbrowser actually requests the image content.
E.g.
<p:dataTable value="#{bean.students}" var="student">
<p:column>
<p:graphicImage value="#{studentImages.image}">
<f:param name="studentId" value="#{student.id}" />
</p:graphicImage>
</p:column>
</p:dataTable>
Where the StudentImages backing bean can look like this:
#Named // Or #ManagedBean
#ApplicationScoped
public class StudentImages {
#EJB
private StudentService service;
public StreamedContent getImage() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the HTML. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
}
else {
// So, browser is requesting the image. Return a real StreamedContent with the image bytes.
String studentId = context.getExternalContext().getRequestParameterMap().get("studentId");
Student student = studentService.find(Long.valueOf(studentId));
return new DefaultStreamedContent(new ByteArrayInputStream(student.getImage()));
}
}
}
Please note that this is a very special case wherein performing business logic in a getter method is completely legit, considering how the <p:graphicImage> works under the covers. Invoking business logic in getters is namely usually frowned upon, see also Why JSF calls getters multiple times. Don't use this special case as excuse for other standard (non-special) cases. Please also note that you can't make use of EL 2.2 feature of passing method arguments like so #{studentImages.image(student.id)} because this argument won't end up in the image URL. Thus you really need to pass them as <f:param>.
If you happen to use OmniFaces 2.0 or newer, then consider using its <o:graphicImage> instead which can be used more intuitively, with an application scoped getter method directly delegating to the service method and supporting EL 2.2 method arguments.
Thus so:
<p:dataTable value="#{bean.students}" var="student">
<p:column>
<o:graphicImage value="#{studentImages.getImage(student.id)}" />
</p:column>
</p:dataTable>
With
#Named // Or #ManagedBean
#ApplicationScoped
public class StudentImages {
#EJB
private StudentService service;
public byte[] getImage(Long studentId) {
return studentService.find(studentId).getImage();
}
}
See also the blog on the subject.

Try including a mime type. In your posted example, you have it as "". The blank image may be because it doesn't recognize the stream as a image file since you made that field an empty string. So add a mime type of image/png or image/jpg and see if that works:
String mimeType = "image/jpg";
StreamedContent file = new DefaultStreamedContent(bytes, mimeType, filename);

There's a couple possibilities here (and please post the entire class if this isn't it).
1) You're not initializing the image properly
2) Your stream is empty so you're getting nothing
I'm assuming student.getImage() has a signature of byte[] so first make sure that that data is actually intact and represents an image. Secondly--you're not specifying a content-type which should be "image/jpg" or whatever you're using.
Here's some boilerplate code to check it with, I'm using Primefaces 2 for this.
/** 'test' package with 'test/test.png' on the path */
#RequestScoped
#ManagedBean(name="imageBean")
public class ImageBean
{
private DefaultStreamedContent content;
public StreamedContent getContent()
{
if(content == null)
{
/* use your database call here */
BufferedInputStream in = new BufferedInputStream(ImageBean.class.getClassLoader().getResourceAsStream("test/test.png"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
int val = -1;
/* this is a simple test method to double check values from the stream */
try
{
while((val = in.read()) != -1)
out.write(val);
}
catch(IOException e)
{
e.printStackTrace();
}
byte[] bytes = out.toByteArray();
System.out.println("Bytes -> " + bytes.length);
content = new DefaultStreamedContent(new ByteArrayInputStream(bytes), "image/png", "test.png");
}
return content;
}
}
and some markup...
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.prime.com.tr/ui"
>
<h:head>
</h:head>
<h:body>
<p:graphicImage value="#{imageBean.content}" />
</h:body>
</html>
If that code works then you're set up properly. Despite the fact it is garbage code for the streams (don't use it in production) it should give you a point to troubleshoot from. My guess is that you might have something happening in your JPA or other Database framework where you're byte[] is empty or it is formatted wrong. Alternatively you could just have a content-type problem.
Lastly, I would clone the data from the bean so that student.getImage() would only be copied into a new array and then used. This way if you have something unknown going on (something else moving the object or changing the byte[] you're not messing with your streams.
Do something like:
byte[] data = new byte[student.getImage().length]
for(int i = 0; i < data.length; i++)
data[i] = student.getImage()[i];
so that your bean has a copy (or Arrays.copy()--whatever floats your boat). I can't stress enough how something simple like this/content type is usually what's wrong. Good luck with it.

The answer from BalusC is (as usual) the correct one.
But keep one thing (as already stated by him) in mind. The final request is done from the browser to get the URL from the constructed <img> tag. This is not done in a 'jsf context'.
So if you try to e.g. access the phaseId (logging or whatever reason)
context.getCurrentPhaseId().getName()
This will result in a NullPointerException and the somehow misleading error message you will get is:
org.primefaces.application.resource.StreamedContentHandler () - Error in streaming dynamic resource. Error reading 'image' on type a.b.SomeBean
It took me quite some time to figure out what was the problem.

Related

Primefaces timeline onchanged executes but does not call method on bean

I am attempting to add primefaces to an existing Spring/JSF (myfaces) project. I have the actual timeline component working (or at least loading with the correct data), but the event listeners don't seem to work correctly. I have tried a number of configurations but can't seem to resolve this issue.
<p:timeline id="timeline1"
value="#{timelineView.getModel(searchFacade.dataModel)}"
editable="true" eventMargin="10" eventMarginAxis="0"
start="#{timelineView.start}"
end="#{timelineView.end}"
showNavigation="true" showButtonNew="true"
axisOnTop="true" stackEvents="false"
oncomplete="styleEvents();">
<p:ajax event="changed" listener="#{timelineView.onEdit()}" oncomplete="restyleTimeline()" />
</p:timeline>
In the above code the changed event is triggered and there is an AJAX call made. In the network pane of the browser I can see that the AJAX call is always to the URL of the current page (so like /mypage.jsf?conversationCode=a - I'm also using Apache Orchestra obviously)
The actual form data being sent for the changed event looks like this:
javax.faces.partial.ajax:true
javax.faces.source:timeline1
javax.faces.partial.execute:timeline1
javax.faces.behavior.event:changed
javax.faces.partial.event:changed
timeline1_eventIdx:0
timeline1_startDate:1498881600000
timeline1_endDate:1510894800000
timeline1_group:<div class='timeline-group'><div class='timeline-row timeline-row-group'>Group One/div><div class='timeline-row timeline-row-sub'>Group One subtitle</div><div class='timeline-row timeline-row-details'>Group One details</div></div>
mainForm:j_id_mt_SUBMIT:1
javax.faces.ViewState: Big hash as usual
The bizarrely long group name is because I am formatting the output group names into a more detailed title for the row btw.
The bean in the back (imports and package omitted):
public class TimelineView<T> implements Serializable {
private static final long serialVersionUID = 1L;
TimelineView<T> timelineView;
public TimelineModel getModel() {
return timelineView.getModel();
}
public TimelineModel getModel(ListDataModel<? extends Row<T>> results) {
return timelineView.getModel(results);
}
public void setTimelineView(TimelineView<T> timelineView) {
this.timelineView = timelineView;
}
public Date getStart() {
return timelineView.getStart();
}
public Date getEnd() {
return timelineView.getEnd();
}
public void onEdit(TimelineModificationEvent e) {
timelineView.onEdit(e);
}
public void onSelect(TimelineSelectEvent e) {
timelineView.onSelect(e);
}
}
The functionality and code inside these methods doesn't matter because when I set a breakpoint I can see that the onEdit method is never called and neither was the onSelect method when I had a select event in the timeline.
Since I have Spring handling all beans, my configuration was just this, located in the ApplicationContext.xml file:
<bean id="timelineView" class="com.mycompany.projectone.view.timeline.TimelineView" />
I have tried adding a form around the timeline, which made no difference, and have also tried adding process=":form_id", which caused the error "Cannot find component for expression ":form_id"".
As an alternative that would also suit my needs, does anyone know how to send primefaces events to a javascript function to be handled? For example, if the user moves the start and end points of the item in the timeline I would like to update the displayed start and end dates.
I would also like to change or intercept the delete behavior and modify what occurs when the delete link is clicked.
Any help would be hugely appreciated. Thanks.
EDIT
The suggested potential duplicate does not address the symptoms nor the actual solution - see answer below.
Okay, so the answer turns out to be that the Primfaces timeline component must have a widgetVar set in order for the p:ajax and pe:javascript calls to work. Incredibly simple solution but so infuriatingly difficult to find.

jsf programmatically ajax function call

I am looking for a possibility to write programmatically ajax call on every element.
I have to ways, to build the UI Components
first - panelGroup binding- )
HtmlSelectOneMenu HSOM = new HtmlSelectOneMenu();
UISelectItems items = new UISelectItems();
List<SelectItem> comboList = new ArrayList<SelectItem>();
comboList.add(new SelectItem(" "));
comboList.add(new SelectItem("1"));
comboList.add(new SelectItem("2"));
comboList.add(new SelectItem("3"));
items.setValue(comboList);
HSOM.getChildren().add(items);
HSOM.setValueExpression("value", buildValueExpression("#{productDetails.productOptionValue}"));
AjaxBehavior ajax = new AjaxBehavior();
ajax.setValueExpression("value", buildValueExpression("#{productDetails.updateProduct()}"));
HSOM.addClientBehavior("valueChange", ajax);
HSOM.addValidator(new BeanValidator());
productOptions.getChildren().add(HSOM);
private ValueExpression buildValueExpression(String exp) {
FacesContext facesInstance = FacesContext.getCurrentInstance();
Application application = facesInstance.getApplication();
ExpressionFactory expressionFactory = application.getExpressionFactory();
String expression = exp;
return expressionFactory.createValueExpression(facesInstance.getELContext(), expression, String.class);
}
I can see, that a Ajax Call is linked to the component, but the updateProduct() function did not get called.
the other possibility to create the dynamic components is)
public void encodeEnd(FacesContext context) throws IOException {
System.out.println("Start encoding");
ResponseWriter responseWriter = context.getResponseWriter();
responseWriter.startElement("span", null);
responseWriter.writeAttribute("id",getClientId(context),"id");
responseWriter.writeAttribute("name", getClientId(context),"clientId");
responseWriter.write("Farbe");
responseWriter.endElement("span");
responseWriter.startElement("select", null);
responseWriter.writeAttribute("id",getClientId(context),"id");
responseWriter.writeAttribute("name", getClientId(context),"clientId");
responseWriter.writeAttribute("value", "#{artikelDetails.productOptionValue}", "value");
responseWriter.startElement("option", null);
responseWriter.write("Gelb");
responseWriter.endElement("option");
responseWriter.startElement("option", null);
responseWriter.write("Blau");
responseWriter.endElement("option");
responseWriter.endElement("select");
System.out.println("End encoding");
}
How to add a ajax call on every select ele here ?
And which of both method's do you prefer ?
This is a very simple example, where i do not build lot of select ele via loop
first i need to get this work...
You need to give all programmatically created input and command components a fixed ID, so that JSF can find the desired submitted information in the request parameter map. Otherwise they end up getting an autogenerated ID which is different during postback.
In your case, that's thus:
HSOM.setId("someId");
And which of both method's do you prefer ?
None of both. I'm confident that Java is the wrong tool for the purpose of declaring components in the view. JSF already ships with Facelets out the box which allows declaring components in a much easier and cleaner way by XML means. If you intend to build the view dynamically based on some preconditions, look at JSTL. See also among others How to make a grid of JSF composite component? and JSTL in JSF2 Facelets... makes sense?

Rendering ClientBehaviorHolder

I am busy writing my own JSF2 UIComponents and their relevant renderers. All of my UIComponents implements ClientBehaviorHolder. What I don't understand is how to really render ClientBehaviorHolder.
For example, the following code illustrates how ClientBehaviorHolder is rendered in Mojarra.
private static void renderHandler(FacesContext context,
UIComponent component,
Collection<ClientBehaviorContext.Parameter> params,
String handlerName,
Object handlerValue,
String behaviorEventName,
String submitTarget,
boolean needsSubmit,
boolean includeExec)
throws IOException {
ResponseWriter writer = context.getResponseWriter();
String userHandler = getNonEmptyUserHandler(handlerValue);
List<ClientBehavior> behaviors = getClientBehaviors(component, behaviorEventName);
// Don't render behavior scripts if component is disabled
if ((null != behaviors) &&
(behaviors.size() > 0) &&
Util.componentIsDisabled(component)) {
behaviors = null;
}
if (params == null) {
params = Collections.emptyList();
}
String handler = null;
switch (getHandlerType(behaviors, params, userHandler, needsSubmit, includeExec)) {
case USER_HANDLER_ONLY:
handler = userHandler;
break;
case SINGLE_BEHAVIOR_ONLY:
handler = getSingleBehaviorHandler(context,
component,
behaviors.get(0),
params,
behaviorEventName,
submitTarget,
needsSubmit);
break;
case SUBMIT_ONLY:
handler = getSubmitHandler(context,
component,
params,
submitTarget,
true);
break;
case CHAIN:
handler = getChainedHandler(context,
component,
behaviors,
params,
behaviorEventName,
userHandler,
submitTarget,
needsSubmit);
break;
default:
assert(false);
}
writer.writeAttribute(handlerName, handler, null);
}
For submit handlers, Mojarra adds the mojarra.jsfcljs javascript, UIParameters and other scripts. For chain handlers, jsf.util.chain is used.
My question is:
How does one determine if we have to render handlers in chain or a single behaviour or user specific handler?
mojarra.jsfcljs is only unique to Mojarra. PrimeFaces have their own implementation, so does Apache Tomahawk. Question is: what does mojarra.jsfcljs do and what is its use? This is so that I can write one for my own? Also, where can I find the implementation of mojarra.jsfcljs?
What is the specification to render ClientBehaviorHolder?
My sincere thanks in advance.
How does one determine if we have to render handlers in chain or a single behaviour or user specific handler?
Imagine that the enduser (read: the JSF developer who's using your component) programmed:
<your:component onclick="return foo()" />
And you intented to ultimately render for your component's own purpose:
<someHtmlElement onclick="jsf.ajax.request(...); return false;" />
Then you can't just concatenate the enduser's onclick in front of your component's jsf.ajax.request() like so
<someHtmlElement onclick="return foo(); jsf.ajax.request(...); return false;" />
Even if it returned true, your component's jsf.ajax.request won't be invoked at all. You ultimately want to end up something like:
<someHtmlElement onclick="if returnsTrue('return foo();') { jsf.ajax.request(...); } return false;" />
That's exactly what jsf.util.chain() is doing under the covers.
mojarra.jsfcljs is only unique to Mojarra. PrimeFaces have their own implementation, so does Apache Tomahawk. Question is: what does mojarra.jsfcljs do and what is its use? This is so that I can write one for my own? Also, where can I find the implementation of mojarra.jsfcljs?
It's inside the jsf.js file. Easy way to find it is to open a JSF page with <f:ajax> embedded and look in the generated <head> source for the <script> with its URL. This file is by default minified. If you set javax.faces.PROJECT_STAGE context param to Development, then this will be served unminified. The task of the jsfcljs() function is to submit the parent form with the necessary parameters. Here's an extract of relevance coming from Mojarra 2.1.21.
/*
* This is called by command link and command button. It provides
* the form it is nested in, the parameters that need to be
* added and finally, the target of the action. This function
* will delete any parameters added <em>after</em> the form
* has been submitted to handle DOM caching issues.
*
* #param f - the target form
* #param pvp - associative array of parameter
* key/value pairs to be added to the form as hidden input
* fields.
* #param t - the target of the form submission
*/
mojarra.jsfcljs = function jsfcljs(f, pvp, t) {
What is the specification to render ClientBehaviorHolder?
Use ClientBehavior#getScript() to get the autogenerated script. It requires a ClientBehaviorContext argument which can be created using ClientBehaviorContext#createClientBehaviorContext(). It's in turn your responsibility to render it into the appropriate HTML attribute, such as onclick.
FacesContext context = FacesContext.getCurrentInstance();
UIComponent inputOrCommandComponent = ...; // Your component.
String event = "click"; // Just the particular HTML DOM event name you need to listen on.
ClientBehaviorContext clientBehaviorContext = ClientBehaviorContext.createClientBehaviorContext(context, component, event, component.getClientId(context), null);
StringBuilder builder = new StringBuilder();
for (ClientBehavior behavior : component.getClientBehaviors().get(event)) { // Collect all <f:ajax> declarations on the given event.
builder.append(behavior.getScript(clientBehaviorContext));
builder.append(';');
}
String script = builder.toString();
// Write it to the desired HTML attribute.
Note that you absolutely don't need to worry about writing JSF implementation specific scripts this way. They will be generated for you.
All with all, ClientBehaviorHolder is just an abstraction of ajax support. It allows developers to nest <f:ajax> in your component. All standard JSF UIInput and UICommand components implement it.

tapestry display blob using markup

I have saved blob image in db, using this component I wish to embed blob from mysql to tag in tapestry.
I have found this on the net.
Do not understand how writer.element works
I think something like this should work
#SupportsInformalParameters
public class DBImage {
#Parameter(required = true)
private Image image;
#Inject
private ComponentResources resources;
boolean beginRender(MarkupWriter writer,byte[] array){
writer.element("img", "src", "data:image/png;base64,"+array,);
resources.renderInformalParameters(writer);
writer.end();
return false;
}
}
than call the component every on page class
#Property
private DBImage image.beginRedner(entity.getBlobImage);
I haven't tried to use the data uri scheme with images in tapestry - i'm sure it 'can' work, but to call the you'd just include this in your tml:
<t:DBImage image="${entity.BlobImage}" />
and within your DBImage component you'll need a way to convert the image parameter into a byte array.
I don't want to take the time to create a working example of this technique, but i'll take you through how I solve this type of problem:
Just like with any image render within an html document, there MUST be two separate requests (unless using the data uri scheme):
the page's html to render the image tag (ie http://host/context/app/mypage)
the image data (ie http://host/context/app/myimage)
so for request one, you want to construct the image url and put it in an img tag:
<html>
...
<img src="/context/app/myimage/params" />
...
</html>
and request two will just return the byte stream of the image data.
Lets start with the second request, because it makes more sense that way.
In tapestry, an individual request is handled by creating a page class and optionally tml template. To serve a byte stream, you just need the page class. To pass parameters or context to the page, you use context params.
package myproject.pages;
public class MyImage
{
public StreamResponse onActivate(String parameter)
{
// retrieve your image using the context parameter(s)
final InputStream imageStream = getImage(parameter);
return new StreamResponse()
{
#Override
public InputStream getStream() throws IOException
{
return imageStream;
}
#Override
String getContentType()
{
return "image/png";
}
#Override
void prepareResponse(Response response)
{}
};
}
}
At this point, you can request/render your image using the url "http://host/context/app/myimage/parameter". Now you just need to include this in your img tag, ie request 1.
So you'll need to generate the link first, which needs to be done in your page class:
package myproject.pages;
public class MyPage
{
#Inject
private PageRenderLinkSource pageLink;
public Link getImageLink()
{
return pageLink.createPageRenderLinkWithContext(MyImage.class, parameter);
}
}
All thats left is to use this link in your tml:
<img src="${imageLink}" />
Obviously you need to wire up your parameter and retrieval.

Performance of resolving EL Value Expressions

I have a JSF2 application that renders a large table with complex content. Unfortunately, each request takes up to 6 seconds to process. Using simple debug output inside a phase listener, I could see that the performance loss distributes evenly over all phases that process the component tree. So I started up a profiler to see what's going on in detail and found out that over 300.000 ValueExpressions are evaluated during one simple request.
They resolve to really simple getters without any logic, so the problem is not executing the code behind these expressions but parsing the expression string and invoking the getter methods. This leads to a few questions:
1.) Is there any way to speed up the resolving of method expressions. Maybe a hidden "enable caching" flag or something.
2.) It seems most of the expressions are evaluated not inside the render response phase, where they are actually needed, but during the other phases. It seems unnecessary to resolve for example styleClass during any other phase than the render phase. Can I prevent this?
3.) Of course, minimizing the number of EL expressions in my facelets page should help getting more performance, but it seems that I cannot really do this: Many attributes (like the styleClass example mentioned above) are actually dependent on the table row, but can only be set on the column. So, having 10 columns, each expression is evaluated much too often. I've seen examples where the rowClasses attribute of the table is used to conditionally style the rows, but as the table is sortable, that won't work without rolling my own sorting mechanism. Is there a better way to implement this?
4.) One more simple question: Is there a way to cache variables in the component tree (just like ui:repeat provides access to the contents of a list and resolves the expression to get the list only once, but just for one variable)?
Thank you very much for all answers and hints!
EDIT:
After further investigation, I found out that for each rendered=#{someExpression}, the expression is evaluated 6 times per row just during the render response phase. I know that JSF may call my getters more than once, but I thought this would be because they can be called inside each phase. During rendering, that values shouldn't change, so I guess they could be cached.
Stepping through the code in the debugger, it looks like javax.faces.component.ComponentStateHelper (which appears in each of the stack traces leading to the evaluated method call) provides a map to do exactly this kind of caching. However, this doesn't seem to work as I expect and always re-evaluates the expression...
1.) Is there any way to speed up the resolving of method expressions. Maybe a hidden "enable caching" flag or something.
No one comes to mind.
2.) It seems most of the expressions are evaluated not inside the render response phase, where they are actually needed, but during the other phases. It seems unnecessary to resolve for example styleClass during any other phase than the render phase. Can I prevent this?
This should as far as I know not happen. The only ones which could/should be resolved before render response are rendered, required, disabled, readonly and value.
3.) Of course, minimizing the number of EL expressions in my facelets page should help getting more performance, but it seems that I cannot really do this: Many attributes (like the styleClass example mentioned above) are actually dependent on the table row, but can only be set on the column. So, having 10 columns, each expression is evaluated much too often. I've seen examples where the rowClasses attribute of the table is used to conditionally style the rows, but as the table is sortable, that won't work without rolling my own sorting mechanism. Is there a better way to implement this?
You could hand over the styling work to a smart piece/combination of JS/CSS.
4.) One more simple question: Is there a way to cache variables in the component tree (just like ui:repeat provides access to the contents of a list and resolves the expression to get the list only once, but just for one variable)?
Use JSTL <c:set>. I am not sure how that would affect after all, but you're then basically only moving the problem to somewhere else. A #{variableName} would still have a cost of locating it in any of the scopes. You can also consider to name the scope explicitly when accessing the variable. E.g. #{sessionScope.beanname} which should skip unnecessarily scanning in page and request scopes.
I know this one is kinda old but I want to add that this issue has been solved by the MyFaces implementation. It is documented in their Wiki: https://cwiki.apache.org/confluence/display/MYFACES/Cache+EL+Expressions
If you are using the mojarra reference implementation on glassfish you might try a nightly build as mentioned in this blog post by Ed Burns. There were some performance improvements contributed by the oracle adf developers relating to el expression evaluation.
Not sure if this is related, but you might also try to disable partial state saving by setting the init parameter javax.faces.PARTIAL_STATE_SAVING to false.
I suffer from repetitive getter calls on managed bean when using composite component, especially rendered getter is called million times. I do not know whether you use them too but I would like your opinion on my cacheing solution.
I succeeded with some cacheing behavior when I followed BalusC's backing component hint in the question Binding a managed bean instance to composite component.
Composite component:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<!-- INTERFACE -->
<composite:interface componentType="fieldComponentType">
<composite:attribute name="id" type="java.lang.String" required="true" />
<composite:attribute name="label" type="java.lang.String" required="true"/>
<composite:attribute name="toBeRendered" type="java.lang.Boolean" required="true" />
<composite:attribute name="currentValue" required="true" />
</composite:interface>
<!-- IMPLEMENTATION -->
<composite:implementation>
<h:panelGrid rendered="#{cc._toBeRendered}" columns="3">
<h:outputText value="#{cc._label}:"/>
<h:inputText id="#{cc.attrs.id}" rendered="#{cc._toBeRendered}"
value="#{cc.attrs.currentValue}" />
</h:panelGrid>
</composite:implementation>
</html>
Backing component which provides caching within one phase:
package cz.kamosh;
import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
#FacesComponent(value = "fieldComponentType")
public final class FieldComponentType extends UIComponentBase implements NamingContainer {
static class Setting {
String label;
Boolean toBeRendered;
#Override
public String toString() {
return "Setting [label=" + label + ", toBeRendered=" + toBeRendered
+ "]";
}
}
int lastPhaseId = -1;
Setting currentSetting = null;
public FieldComponentType() {
System.out.println("Constructor FieldComponentType");
}
#Override
public String getFamily() {
return "javax.faces.NamingContainer";
}
// Must be named with prefix _, otherwise infinite loop occurs
public String get_label() {
Setting setting = getSetting();
if (setting.label == null) {
setting.label = (String) getAttributes().get("label");
}
return setting.label;
}
// Must be named with prefix _, otherwise infinite loop occurs
public boolean is_toBeRendered() {
Setting setting = getSetting();
if (setting.toBeRendered == null) {
setting.toBeRendered = (Boolean) getAttributes().get("toBeRendered");
}
return setting.toBeRendered;
}
private Setting getSetting() {
int phaseId = FacesContext.getCurrentInstance().getCurrentPhaseId()
.getOrdinal();
if (currentSetting == null || phaseId > lastPhaseId) {
currentSetting = new Setting();
lastPhaseId = phaseId;
}
return currentSetting;
}
}
Testing page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:util="http://java.sun.com/jsf/composite/components">
<h:head>
<title>Testing page</title>
</h:head>
<h:body>
<h:form>
<h:panelGrid>
<util:fieldComponent id="id3"
label="#{testingBean.label}"
toBeRendered="#{testingBean.toBeRendered}"
currentValue="#{testingBean.myValue}" />
</h:panelGrid>
<h:commandButton value="Do something" actionListener="#{testingBean.doSomething}" />
</h:form>
</h:body>
</html>
Managed bean:
package cz.kamosh;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ViewScoped
#ManagedBean(name="testingBean")
public class TestingBean {
private String myValue;
public String getMyValue() {
System.out.printf("getMyValue: %1$s\n", myValue);
return myValue;
}
public void setMyValue(String myValue) {
System.out.printf("setMyValue: %1$s\n", myValue);
this.myValue = myValue;
}
public void doSomething() {
System.out.printf("Do something, myValue: %1$s\n", this.myValue);
}
public String getLabel() {
System.out.printf("getLabel\n");
return "My value lbl";
}
public boolean isToBeRendered() {
System.out.printf("isToBeRendered\n");
return true;
}
}
After being profiled using jvisualvm 26 calls of com.sun.faces.facelets.el.TagValueExpression.getValue decreased from 26% to 16% of overall time spent in one complete request 'run' (compared with composite component which does not make use of componentType="fieldComponentType" - sources not included in this answer).
But anyway overhead of JSF2 framework itself costs about 80% of time compared to 20% spent in my code even if I call some database fetches (this is my experience from our production code). And I consider this overhead quite big :-(
#FRoothowe you mentioned that "During rendering, that values shouldn't change, so I guess they could be cached." From this point of view I can afford cacheing tag expression values within each phase, am I right?
After couple of hours of debugging I decided to improve ComponentStateHelper which is part of Mojarra JSF2 implementation.
I took the last version 2.1.4 https://maven.java.net/content/repositories/releases/org/glassfish/javax.faces/2.1.4/javax.faces-2.1.4-sources.jar
The main idea is to preserve results of EL expressions evaluated during each phase. I am still assuming that result of EL expression must be the same within one phase.
Changes in class javax.faces.component.ComponentStateHelper:
class ComponentStateHelper implements StateHelper , TransientStateHelper {
...
// Own cache for method public Object eval(Serializable key, Object defaultValue) {
int lastPhaseId = -1; // Last cached phase
private Map<Serializable, Object> evalCache;
...
public ComponentStateHelper(UIComponent component) {
...
// Instantiate own cache
this.evalCache = new HashMap<Serializable, Object>();
}
...
/**
* #see StateHelper#eval(java.io.Serializable, Object)
*/
public Object eval(Serializable key, Object defaultValue) {
Object retVal = get(key);
if (retVal == null) {
// Value evaluated and returned within one phase should be hopefully still same
int currentPhaseId = FacesContext.getCurrentInstance().getCurrentPhaseId().getOrdinal();
if(lastPhaseId < currentPhaseId) {
// Probably stale cache, so clear it to get fresh results
// in current phase
evalCache.clear();
lastPhaseId = currentPhaseId;
}
retVal = evalCache.get(key);
if(retVal == null) {
ValueExpression ve = component.getValueExpression(key.toString());
if (ve != null) {
retVal = ve.getValue(component.getFacesContext().getELContext());
}
}
// Remember returned value in own cache
evalCache.put(key, retVal);
}
return ((retVal != null) ? retVal : defaultValue);
}
...
}
This enhancement seems to be functional and number of calls to my managed bean decreased drastically, especially rendered getters which were called multiple times for the same component.
I maybe do not see what disasterous consequences this enhancement may cause. But if this is feasable I wonder why JSF guys have not used this type of cacheing.
*EDIT: This solution cannot be used as it has problems when combined with DataModel!!! *

Resources