Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Load Font from /WEB-INF/resources/fonts/foobar.ttf with iTextPdf FontFactory

The question pretty much says it all. I get following exception:

ExceptionConverter: java.io.IOException: /fonts/CALIBRI.TTF not found as file or resource.
Caused By: java.io.IOException: /fonts/CALIBRI.TTF not found as file or resource.
    at com.itextpdf.text.io.RandomAccessSourceFactory.createByReadingToMemory(RandomAccessSourceFactory.java:263)
    at com.itextpdf.text.io.RandomAccessSourceFactory.createBestSource(RandomAccessSourceFactory.java:173)
    at com.itextpdf.text.pdf.RandomAccessFileOrArray.<init>(RandomAccessFileOrArray.java:148)
    at com.itextpdf.text.pdf.TrueTypeFont.process(TrueTypeFont.java:641)
    at com.itextpdf.text.pdf.TrueTypeFont.<init>(TrueTypeFont.java:375)
    at com.itextpdf.text.pdf.BaseFont.getAllFontNames(BaseFont.java:1229)
    at com.itextpdf.text.FontFactoryImp.register(FontFactoryImp.java:446)
    at com.itextpdf.text.FontFactory.register(FontFactory.java:341)
    at bean.createPdf.makePdf(createPdf.java:358)
    at bean.auswahl.buttonProbenbegleitschein(auswahl.java:188)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.sun.el.parser.AstValue.invoke(AstValue.java:254)
    at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:302)
    at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
    at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:148)
    at javax.faces.event.ActionEvent.processListener(ActionEvent.java:88)
    at org.apache.myfaces.trinidad.component.UIXComponentBase.broadcast(UIXComponentBase.java:1113)
    at org.apache.myfaces.trinidad.component.UIXCommand.broadcast(UIXCommand.java:179)
    at org.apache.myfaces.trinidad.component.UIXComponent.broadcastInContext(UIXComponent.java:364)
    at oracle.adf.view.rich.event.ProxyEvent.broadcastWrappedEvent(ProxyEvent.java:72)
    at oracle.adf.view.rich.component.fragment.UIXRegion.broadcast(UIXRegion.java:124)
    at org.apache.myfaces.trinidad.component.UIXComponent.broadcastInContext(UIXComponent.java:364)
    at org.apache.myfaces.trinidad.component.WrapperEvent.broadcastWrappedEvent(WrapperEvent.java:82)
    at oracle.adf.view.rich.component.fragment.ContextSwitchingComponent$1.run(ContextSwitchingComponent.java:168)
    at oracle.adf.view.rich.component.fragment.ContextSwitchingComponent._processPhase(ContextSwitchingComponent.java:510)
    at oracle.adf.view.rich.component.fragment.ContextSwitchingComponent.broadcast(ContextSwitchingComponent.java:171)
    at org.apache.myfaces.trinidad.component.UIXComponent.broadcastInContext(UIXComponent.java:364)
    at org.apache.myfaces.trinidad.component.WrapperEvent.broadcastWrappedEvent(WrapperEvent.java:82)
    at oracle.adf.view.rich.component.fragment.UIXInclude.broadcast(UIXInclude.java:111)
    at org.apache.myfaces.trinidad.component.UIXComponent.broadcastInContext(UIXComponent.java:364)
    at org.apache.myfaces.trinidad.component.WrapperEvent.broadcastWrappedEvent(WrapperEvent.java:82)
    at oracle.adf.view.rich.component.fragment.ContextSwitchingComponent$1.run(ContextSwitchingComponent.java:168)
    at oracle.adf.view.rich.component.fragment.ContextSwitchingComponent._processPhase(ContextSwitchingComponent.java:510)
    at oracle.adf.view.rich.component.fragment.ContextSwitchingComponent.broadcast(ContextSwitchingComponent.java:171)
    at oracle.adf.view.rich.component.fragment.UIXInclude.broadcast(UIXInclude.java:115)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._invokeApplication(LifecycleImpl.java:1074)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._executePhase(LifecycleImpl.java:402)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:225)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:280)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:254)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:136)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:346)
    at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:25)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at oracle.adf.model.servlet.ADFBindingFilter.doFilter(ADFBindingFilter.java:192)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at oracle.adfinternal.view.faces.webapp.rich.RegistrationFilter.doFilter(RegistrationFilter.java:105)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:502)
    at oracle.adfinternal.view.faces.activedata.AdsFilter.doFilter(AdsFilter.java:60)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:502)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl._doFilterImpl(TrinidadFilterImpl.java:327)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl.doFilter(TrinidadFilterImpl.java:229)
    at org.apache.myfaces.trinidad.webapp.TrinidadFilter.doFilter(TrinidadFilter.java:92)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at de.lkvsh.rdv.portal.authlib.servlet.PortalFilter.doFilter(PortalFilter.java:116)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at oracle.security.jps.ee.http.JpsAbsFilter$1.run(JpsAbsFilter.java:137)
    at java.security.AccessController.doPrivileged(Native Method)
    at oracle.security.jps.util.JpsSubject.doAsPrivileged(JpsSubject.java:315)
    at oracle.security.jps.ee.util.JpsPlatformUtil.runJaasMode(JpsPlatformUtil.java:460)
    at oracle.security.jps.ee.http.JpsAbsFilter.runJaasMode(JpsAbsFilter.java:120)
    at oracle.security.jps.ee.http.JpsAbsFilter.doFilter(JpsAbsFilter.java:217)
    at oracle.security.jps.ee.http.JpsFilter.doFilter(JpsFilter.java:81)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at oracle.dms.servlet.DMSServletFilter.doFilter(DMSServletFilter.java:220)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at weblogic.servlet.internal.RequestEventsFilter.doFilter(RequestEventsFilter.java:27)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3436)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3402)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
    at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
    at weblogic.servlet.provider.WlsSubjectHandle.run(WlsSubjectHandle.java:57)
    at weblogic.servlet.internal.WebAppServletContext.doSecuredExecute(WebAppServletContext.java:2285)
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2201)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2179)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1572)
    at weblogic.servlet.provider.ContainerSupportProviderImpl$WlsRequestExecutor.run(ContainerSupportProviderImpl.java:255)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:311)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:263)

Physical location of font file is /WEB-INF/resources/fonts/CALIBRI.TTF So as far as I see it, it can't be not found in resources by iTextPDf FontFactory.

like image 829
m3t4lukas Avatar asked Feb 09 '23 05:02

m3t4lukas


1 Answers

Based on the source code of iText's RandomAccessSourceFactory#createBestSource(), the FontFactory#register() can only take a path representing a valid (relative) disk file system path, or a resource URL (e.g. HTTP URL or classpath URL), not a WAR resource path. You actually supplied a WAR resource path which you can usually pass to ServletContext#getResource(), getResourceAsStream(), getRealPath() and getRequestDispatcher() only.

There are several ways to get it to work:

  1. Convert the WAR resource path to an absolute disk file system path with help of ServletContext#getRealPath():

    String path = getServletContext().getRealPath("/WEB-INF/resources/fonts/foobar.ttf");
    FontFactory.register(path);
    

    The caveat is that this method is highly unportable and environment-dependent. Among others, this will fail when the server is configured to expand the WAR straight into memory instead of on local disk file system, or uses a virtual file system. E.g., by default, it may work on Tomcat, but it may not work on WebLogic. Your stack trace confirms that you're using WebLogic. The chance is big that the getRealPath() will by default always return null.


  2. Move the font file outside /WEB-INF folder so that it's publicly accessible by a HTTP URL. Provided that you can move whole /resources folder one level up, outside /WEB-INF, and that the font is accessible by http://localhost:8080/context/resources/fonts/foobar.ttf (first test in a normal webbrowser to be sure), then just supply exactly that path.

    String path = "http://localhost:8080/context/resources/fonts/foobar.ttf";
    FontFactory.register(path);
    

    You can if necessary dynamically construct http://localhost:8080/context (the base URL) as below:

    String url = request.getRequestURL().toString();
    String baseURL = url.substring(0, url.length() - request.getRequestURI().length()) + request.getContextPath();
    String path = baseURL + "/resources/fonts/foobar.ttf";
    FontFactory.register(path);
    

    The caveat is that, by default, anyone in the world could download it, even when only guessing the URL.


  3. Move the font file to the classpath. I.e. make sure it ultimately ends up in /WEB-INF/classes among all those Java class files and class resource files (such as properties files). Let's assume that the package name is just fonts. In case you're using Maven, just put it in /main/resources/fonts/foobar.ttf. In case you're using a "plain vanilla" web project with only a src folder where you put all your Java packages and class source files, then create a package fonts the usual way and put the foobar.ttf file right there. Then you can supply a path of /fonts/foobar.ttf.

    String path = "/fonts/foobar.ttf";
    FontFactory.register(path);
    

    This is clearly the preferred way.


  4. In case none of above options apply, your last resort is creating a temporary file with help of File#createTempFile() in container managed temporary folder, grabbing the WAR resource contents by ServletContext#getResourceAsStream(), writing it to the temp file and finally provide the absolute temp file path.

    String tempDir = (String) getServletContext().getAttribute(ServletContext.TEMPDIR);
    File tempFile = File.createTempFile("foobar-", ".ttf", new File(tempDir));
    InputStream input = getServletContext().getResourceAsStream("/WEB-INF/resources/fonts/foobar.ttf");
    Files.copy(input, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
    String path = tempFile.getAbsolutePath();
    FontFactory.register(path);
    

Note: the above answer assumes that the code is placed in a "plain" Java EE servlet class. In case you're using JSF — as confirmed by the stack trace — you can obtain the ServletContext by ExternalContext#getContext(), the HttpServletRequest by ExternalContext#getRequest(), the ServletContext attributes by ExternalContext#getApplicationMap(), the real path by ExternalContext#getRealPath(), and the resource stream by ExternalContext#getResourceAsStream().

like image 181
BalusC Avatar answered Feb 11 '23 17:02

BalusC