An error occurred while streaming a dynamic resource. zero

Important Note: This issue has been fixed since PrimeFaces 5.2 final (community release) was released on April 8, 2015. That way, if you accidentally use this version or newer, you won’t have to bother with a temporary workaround.

The earlier example can now be safely modified as follows.

public StreamedContent getImage() throws IOException { FacesContext context = FacesContext.getCurrentInstance(); if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) { return new DefaultStreamedContent(); } else { String id = context.getExternalContext().getRequestParameterMap().get("id"); byte[] bytes = Utils.isNumber(id) ? service.findImageById(Long.parseLong(id)) : null; return bytes == null ? null : new DefaultStreamedContent(new ByteArrayInputStream(bytes)); } } 

I moved the images to the database (MySQL) as a BLOB ( LONGBLOB ) after I got tired of manipulating / managing the images stored in the disk file system.

Accordingly, I show the images in <p:dataTable> as follows (explicitly copied from here :)).

 <p:column headerText="Header"> <p:graphicImage value="#{bannerBean.image}" height="200" width="200"> <f:param name="id" value="#{row.bannerId}"/> </p:graphicImage> <p:column> 

The bean that retrieves the images is as follows.

 @ManagedBean @ApplicationScoped public final class BannerBean { @EJB private final BannerBeanLocal service=null; public BannerBean() {} public StreamedContent getImage() throws IOException { FacesContext context = FacesContext.getCurrentInstance(); if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) { return new DefaultStreamedContent(); } else { String id = context.getExternalContext().getRequestParameterMap().get("id"); byte[] bytes = service.findImageById(Long.parseLong(id)); return bytes==null? new DefaultStreamedContent():new DefaultStreamedContent(new ByteArrayInputStream(bytes)); } } } 

This works fine as long as there are images in each row of the database table.

A column of type BLOB in the database, however, is optional in some cases and, therefore, it may contain null values.

If this column is null on any / s line in the database, the following exception is thrown.

 SEVERE: Error in streaming dynamic resource. null WARNING: StandardWrapperValve[Faces Servlet]: Servlet.service() for servlet Faces Servlet threw exception java.lang.NullPointerException at org.primefaces.application.PrimeResourceHandler.handleResourceRequest(PrimeResourceHandler.java:127) at javax.faces.application.ResourceHandlerWrapper.handleResourceRequest(ResourceHandlerWrapper.java:153) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:643) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:344) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:70) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:316) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188) at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191) at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168) at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189) at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206) at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136) at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114) at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77) at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838) at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544) at java.lang.Thread.run(Thread.java:722) 

So how do you manage a null BLOB to throw this exception?

new DefaultStreamedContent(new ByteArrayInputStream(new byte[0])) returning new DefaultStreamedContent(new ByteArrayInputStream(new byte[0])) , if the byte array in the managed bean is null, it will suppress the exception, but this should not be the solution. Is this a desirable solution?


An EJB method that returns an array of bytes, although in this case it is completely unnecessary.

 public byte[] findImageById(Long id) { CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<byte[]>criteriaQuery=criteriaBuilder.createQuery(byte[].class); Root<BannerImages> root = criteriaQuery.from(BannerImages.class); criteriaQuery.multiselect(root.get(BannerImages_.bannerImage)); ParameterExpression<Long>parameterExpression=criteriaBuilder.parameter(Long.class); criteriaQuery.where(criteriaBuilder.equal(root.get(BannerImages_.bannerId), parameterExpression)); List<byte[]> list = entityManager.createQuery(criteriaQuery).setParameter(parameterExpression, id).getResultList(); return list!=null&&!list.isEmpty()?list.get(0):null; } 
+6
source share
2 answers

This is a bug (at least a functional / technical design bug) in the PrimeResourceHandler . He should not have assumed that a dynamic resource or its content would never be null . He would have to conditionally check if this was the case, and then simply returned an HTTP 404 "Not Found" response.

In other words, instead of

 85 streamedContent = (StreamedContent) ve.getValue(eLContext); 86 87 externalContext.setResponseStatus(200); 88 externalContext.setResponseContentType(streamedContent.getContentType()); 

they had to do

 85 streamedContent = (StreamedContent) ve.getValue(eLContext); 86 87 if (streamedContent == null || streamedContent.getStream() == null) { 88 externalContext.responseSendError(HttpServletResponse.SC_NOT_FOUND, ((HttpServletRequest) externalContext.getRequest()).getRequestURI()); 89 return; 90 } 91 92 externalContext.setResponseStatus(200); 93 externalContext.setResponseContentType(streamedContent.getContentType()); 

That way you can simply return null or empty StreamedContent from the getImage() method to create a decent 404.

OK, what can you do?

  • Report it and hope they fix it. Update They are fixed in version 5.2.

  • And / or add a copy of the PrimeResourceHandler class to the Java source folder of your webapp project, exactly your own org.primefaces.application package, and then just edit it to include the mentioned change, and finally just create / deploy the webapp project as a WAR as usual . Classes in /WEB-INF/classes take precedence over JAR classes in /WEB-INF/lib , so the modified one will be used instead.

+8
source

I would suggest including an attribute in an object that <p:dataTable> to indicate if the image exists. Thus, there are no unnecessary (or null) calls to BannerBean.getImage() .

Example:

 <p:column headerText="Header"> <p:graphicImage value="#{bannerBean.image}" height="200" width="200" rendered="#{row.hasImage}"> <f:param name="id" value="#{row.bannerId}"/> </p:graphicImage> <p:column> 

Another option is to grab the Primefaces source code, edit PrimeResourceHandler.java and create it. (see wiki )


An alternative solution would be to set up your own Serlvet to provide images.

  • The main advantage is that browsers can cache the image (you can specify a cache timeout if you want).
  • Keep in mind SQL Injection and other security attacks.
  • Attach some kind of login / permission check for extra security. (if necessary)

Example:

 <p:column headerText="Header"> <p:graphicImage value="#{request.contextPath}/images/banner/?id=#{row.bannerId}" height="200" width="200" /> <p:column> 
 @WebServlet(name = "Retrieve Banner Images", urlPatterns = "/images/banner/*") public class BannerImageServlet extends HttpServlet { @EJB private final BannerBeanLocal service; protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String[] ids = req.getParameterValues("id"); if(ids != null && ids.length == 1) { byte[] bytes = service.findImageById(Long.parseLong(ids[0])); if(bytes != null) { // see link #3 below } } } } 

Sources / useful links:

+3
source

Source: https://habr.com/ru/post/969870/


All Articles