How can we embed and show an InputStream as dynamic image in JSF 2.0 with OmniFaces?
OmniFaces does not offer any utility for this — yet.
If the image files are located on the disk file system, then you need to create a virtual context in the servletcontainer configuration so that they can be accessed by a normal URL. See also Load images from outside of webapps / webcontext / deploy folder using <h:graphicImage> or <img> tag.
If the image files are stored in the DB, then you need to create a simple servlet which just writes the InputStream of the image from the DB to the OutputStream of the HTTP response. See also How to retrieve and display images from a database in a JSP page? (note that this doesn't require JSP/HTML, you can as good just use <h:graphicImage> as it merely generates a HTML <img> element).
There's the PrimeFaces <p:graphicImage>, but this is a bit unintuitive to implement. See also Display dynamic image from database with p:graphicImage and StreamedContent.
Update: since OmniFaces 2.0 (for JSF 2.2) there's a <o:graphicImage> component which supports among others directly referencing a byte[] or InputStream property in an #ApplicationScoped managed bean in an intuitive way like below:
<o:graphicImage value="#{imageStreamer.getById(bean.imageId)}" />
#Named
#ApplicationScoped
public class ImageStreamer {
#Inject
private ImageService service;
public InputStream getById(Long id) { // byte[] is also supported.
return service.getContent(id);
}
}
In contrary to PrimeFaces <p:graphicImage>, no <f:param> is needed and the EL method arguments are evaluated during render response phase, but the EL method itself is only invoked when the browser actually requests the image. See also the showcase and the blog on the subject.
Related
We have a JSF application with <rich:tab> which shows fields depending of some configuration stored in a database, so the components are not defined in the .xhtml page but have to be generated programmatically such in this example:
Components are generated in a panel:
<rich:tab id="someTab" header="#{msg['someHeader']}" immediate="true">
<rich:messages/>
<h:panelGrid id="generatedComponentsContainer"/>
</rich:tab>
Component generation example (simplified for simplicity):
FacesContext ctx = FacesContext.getCurrentInstance();
UIPanel panel = (UIPanel) ctx.getViewRoot().findComponent("someForm:generatedComponentsContainer");
text = (UIInput) ctx.getApplication().createComponent(ctx, "javax.faces.Input", "javax.faces.component.UIInput");
text.getAttributes().put("label", someLabel);
panel.getChildren().add(text);
Those components have to be shown disabled depending on some condition, so I used the following code to disable each of them if needed:
if (!showEnabled) { text.getAttributes().put("disabled", "true"); }
This method works for UIInput and HtmlInputTextarea but it is not working for UICalendar, throwing a IllegalArgumentException (argument type mismatch).
How can I disable the calendar?
I have been also wondering if this code just disables the component at the client side leaving it enabled at the server. This would probably be a security threat as somebody could enable a component via Javascript and submit the form to the server. I am not sure about this being possible, please advise if I am wrong.
After further research I noticed there are some classes that extend the ones we were using in our project. Those classes have a getter/setter for the disabled attribute which also disables the component in the server side. I tested this disabling the components programmatically and removing the disabled attribute while browsing the page to allow edition and submit. When submitting the form, the values are setted in the request but ignored at the server side. Bean values remain unaltered.
The classes we have used:
HtmlInputTextarea instead of UIInput
HtmlInputText instead of UIInput
We were already using UICalendar, which fits the purpose
A sample of code:
HtmlInputText text = (HtmlInputText) ctx.getApplication().createComponent(
ctx, HtmlInputText.COMPONENT_TYPE, "javax.faces.component.html.HtmlInputText");
if (!showEnabled) { text.setDisabled(true); }
When debugging the contents of the HtmlInputText you can see a ComponentStateHelper object (named stateHelper) which stores the disabled state of the component (among other data). Its superinterface is StateHolder:
public interface StateHolder
This interface is implemented by classes that need to save their state
between requests.
I understand that server-side state of the component is stored in this object, but I am not sure whether it is stored only here or in more points, or even if my interpretation of its purpose is correct. Feedback from an expert would be very useful.
What is the difference between FacesContext and ExternalContext? When can I use one or other? What has the one and what has the other?
The following sample is from the book JavaServer Faces 3rd edition:
<h:commandButton ... actionListener="#{rushmore.handleMouseClick}" />
Backing bean:
public void handleMouseClick(ActionEvent e) {
FacesContext context = FacesContext.getCurrentInstance();
String clientId = e.getComponent().getClientId(context);
Map<String, String> requestParams = context.getExternalContext().getRequestParameterMap();
// ...
}
Why is request parameter in ExternalContext? What is clientId? Is it generated by JSF when the application is started?
Carefully look in their javadocs to see what methods they offer and what exactly those methods all do.
FacesContext javadoc
ExternalContext javadoc
If you look closer at those methods listed in the javadoc, you'll notice that the FacesContext generally offers access to JSF-specific artifacts which are further in no way related to the "underlying" Servlet or Portlet API for which JSF is been designed to run on top of. E.g. creating converters, validators, components, EL expressions, etcetera and obtaining information about view root, supported locales, etcetera and adding phase listeners, system event listeners, etcetera. Everything which is specific to JSF API.
And, ExternalContext generally offers access to Servlet or Portlet-specific artifacts which JSF is currently using "under the covers". E.g., when running on a Servlet container, the HTTP servlet request, HTTP servlet response, HTTP session and Servlet context and inherently also all of their artifacts. Click those links, you'll see that they in turn offer methods which are also been delegated by the ExternalContext, such as getRequestParameterMap(). See also the javadoc. Yes, also click that link, you'll see that it explicitly mentions the servlet request:
Servlet: This must be the set of parameters available via the javax.servlet.ServletRequest methods getParameter() and getParameterNames().
There's nothing which can be offered by the both contexts. So there would be absolutely no reason to prefer the one or the other. Just use the right one for the job you need to perform.
As to the client ID, it's indeed generated by JSF, but definitely not on server's startup. It's just generated for every single JSF component on a per-view basis. In case of input components like <h:inputText>, which generates a HTML <input> element, it also becomes the name attribute like so
<input type="text" id="formId:inputId" name="formId:inputId" ... />
The formId:inputId is exactly the JSF client ID. It becomes the request parameter name. The HTML representation of the command button has also a name which ends up as request parameter name with the button's value as parameter value.
I'm writing an image uploader in Java Play! in the style of
https://gist.github.com/1256286#file-picture-java-L3
This is great. The image is rendered using this function in the Controller object (here, Picture is a Model implementation that has metadata about an image file:
public static void show(Long id) {
Logger.info("loading id=%s", id);
Picture picture = Picture.findByKey(id);
response.setContentTypeIfNotSet(picture.contentType);
renderBinary(new ByteArrayInputStream(picture.file), picture.file.length);
}
I want to add a url member to Picture that contains the absolute URL to this function for a given picture. How can I populate this member in a way that works irrespective of where the Java Play! application is hosted?
Although I didn't try it in version 1.x I suggest to check the Router API, there are some methods which indicates, that they can optionally create an absolute route (I'm Play 2 user and have no experience with them).
There are also methods like ie. getBaseUrl() or getFullUrl(String action, Map<String,Object> args) so I just guess that they probably will help you to resolve the problem.
I'm writing asp.net mvc web application that uses a large number of .jpg files that are on a share folder outside the web server and not accessible via http protocol. How can I place image path inside img tag?
Do not put the image path inside your image tag as a parameter to a script. This is called a direct object reference and is a bad thing. Consider a naive implementation of such a script/page/controller which serves up as /image/?resource=\server\path\img.jpg.
Now what happens if someone loads /image/resource/?resource=c:\windows\system32\config\SAM? Your password database gets sent.
You do not want to use fully qualified paths at all, ideally you want to either serve all images from that directory and just accept a file name, stripping any path information from it by doing something like
string filename = Path.GetFileName(userInputtedFilename);
FileInfo file = new FileInfo(Server.Path.Combine("\\Server\share\", filename)));
That at least is safe, but of course users could browse through all the images if they're suitably named. Safer yet is to have an indirect object reference, a mapping table somewhere which maps something like a GUID to the actual filename and use that as the parameter to your serving script.
To serve a file you return a FileContentResult from your controller,
public FileContentResult GetFile(Guid indirectReference)
{
byte[] fileContents = // Resolve the file and read it from the indirect reference
mimeType = // Suitable MIME type
return File(fileContent, mimeType, fileName);
}
If the web server has regular network access to that share and can read the image files, you can create a new MVC controller Image with default action Index that takes one string parameter called fn. The action would create a new FileResult from the parameter. Then, when you generate the <img> tag, set the url to something like /image/?fn=\\share\image.png. (Don't forget to add the proper route for it, of course)
If the web server has no access to that share, but the page user has access, you can try setting the <img> tag to the file:// URL for the image. However, this is going to be fragile and might or might not work, depending on the user's OS and browser configuration.
Update: Do read the security implications #blowdart mentioned in his answer.
I want to display a list of images and a description on a webpage using ASP.net MVC. The images are stored in a SQL Server DB and i'm getting them back as a byte[].
However, I don't understand how I can display a series of images on a page. I want to do something like this:
<% foreach(Product p in Model.Products)
Response.Write(p.Description)
Response.Write(html.Image(p.ImageArray)
%>
But the only code I've saw has been displaying a single image...
Thank you
Ben
Rather than creating a new HttpHandler you can just write a controller action that returns the contents of the image file. Then add images to the page with their src attribute set to the action you created.
EDIT: Note that streaming images as byte[] from a database is inefficient compared to serving static files.
You will need to create a custom IHttpHandler that will serve the images something like this:
public class AlbumArt : IHttpHandler
{
public void ProcessRequest(HttpContext Context)
{
byte [] b = your image...;
Context.Response.ContentType = "image/jpeg";
Context.Response.BinaryWrite(b);
}
}
And then you would need to retrieve each image from there by using image tags in your html, something like
<img src="AlbumArt.ashx?imageId=1" />
Images in HTML are external links, not embedded in the HTML itself. So you do need two requests. However you can optimize this a bit. In the first request, don't retrieve the image data itself, just the meta-data. Then in your HttpHandler, actually retrieve the binary image data.
Each image will have to be sent separately (which means creating an IMG request from the browser for each) or you will have to join them into a single image before sending back. If you run the code above it is likely you will see the first image only.