javaxsltapache-fop

FOP: Image redirection to server


I am trying to write an embedded custom fop xml to pdf java application using a custom image redirect within fop

I have the following in an old xslt file

      <fo:block text-indent="1mm" padding-before="20mm">
        <xsl:variable name="barcode" select="concat('/prescriptions/', id, '/barcode.html')"/>
        <fo:external-graphic>
          <xsl:attribute name="src">
            <xsl:value-of select="$barcode" />
          </xsl:attribute>
        </fo:external-graphic>
      </fo:block>

I have written a customResourceResolver

package embedding;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.xmlgraphics.io.Resource;
import org.apache.xmlgraphics.io.ResourceResolver;
import java.io.BufferedInputStream;
import java.net.URI;
import java.net.URISyntaxException;

public class CustomResourceResolver implements ResourceResolver {
    String base;
    String session;
    String cookie;
    String user_id;
    String authorization;
    static final Logger logger = Logger.getLogger("fop-log");
    
    public String get_base(){
        return base;
    }
    
    public CustomResourceResolver(String _base, String _session, String _cookie, String _user_id, String _authorization){
        super();
            base = _base;
            session = _session;
            cookie = _cookie;
            user_id = _user_id;
            authorization = _authorization;
    }
    
    @Override
    public Resource getResource(URI uri) throws IOException {          
    HttpURLConnection urlConnection = null;
    try {
      String href = uri.getRawPath();

      if (!href.startsWith("/") && !base.endsWith("/")) {
          base = base + "/";
      }

      String new_uri;
      if (href.startsWith("http://") || href.startsWith("https://")) {
          new_uri = href;
      } else {
          new_uri = base + href;
      }
      
      uri = new URI(new_uri);
      logger.log(Level.INFO, "loading: ({0})", new_uri);
      URL url = uri.toURL();
      
      urlConnection = (HttpURLConnection) url.openConnection();
      if(session!= null){
          urlConnection.setRequestProperty("Cookie", cookie + "=" + session);
      }
      if(authorization != null){
          urlConnection.setRequestProperty("Fop-authorization", authorization );
      }
      if(user_id != null){
          urlConnection.setRequestProperty("Fop-user",user_id );
      }
      
      InputStream in = new BufferedInputStream(urlConnection.getInputStream());
      return new Resource(in);
      
    } catch (MalformedURLException e) {
        logger.log(Level.SEVERE, null, e);
        return null;
    } catch (IOException | URISyntaxException ioe) {
        logger.log(Level.SEVERE, null, ioe);
      return null;
    } finally {
      if (urlConnection != null) {
        urlConnection.disconnect();
      }
    }
    }

    @Override
    public OutputStream getOutputStream(URI uri) throws IOException {
        URL url = uri.toURL();
    return url.openConnection().getOutputStream();
    }
    
}

And this gets called by

CustomResourceResolver resolver = new CustomResourceResolver(base, session, cookie, user_id, authorization);
FopFactoryBuilder builder = new FopFactoryBuilder(new File(".").toURI(), (ResourceResolver)resolver);
final FopFactory fopFactory = builder.build();
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();

OutputStream out = new java.io.FileOutputStream(pdffile);
out = new java.io.BufferedOutputStream(out);
try {
       Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
                
        TransformerFactory factory = TransformerFactory.newInstance();
        URIResolver uiResolver = new CustomUriResolver(base, session, cookie, user_id, authorization);
        
        factory.setURIResolver(uiResolver);
        Transformer transformer = factory.newTransformer(new StreamSource(xsltfile));

        // Set the value of a <param> in the stylesheet
        transformer.setParameter("versionParam", "2.0");

        // Setup input for XSLT transformation
        Source src = new StreamSource(xmlfile);

        // Resulting SAX events (the generated FO) must be piped through to FOP
        Result res = new SAXResult(fop.getDefaultHandler());

        // Start XSLT transformation and FOP processing
        transformer.transform(src, res);
            } finally {
                out.close();
            }

java is packaged inside a single FopXml2Pdf.jar and is called from the command line like

java -jar FopXml2Pdf.jar file.xml file.xsl file.config

but when I run the code I get

Sep 19, 2023 6:52:36 AM embedding.CustomResourceResolver getResource
INFO: loading: (http://localhost:3000/prescriptions/420/barcode.html)
Sep 19, 2023 6:52:36 AM org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext createImageSource
SEVERE: Unable to create ImageInputStream for InputStream from system identifier 'file:/media/sf_Clintel/careright/./' (stream is closed)
Sep 19, 2023 6:52:36 AM org.apache.fop.events.LoggingEventListener processEvent
SEVERE: Image not found. URI: /prescriptions/420/barcode.html. (No context info available)

I can see that the redirection is loading the correct url getting the correct data but

new File(".").toURI() is resolving to file:/media/sf_Clintel/careright/./

What should I set this to so that it saves the data from Resource getResource?


Solution

  • The issue has been solved. packaging of Batik-all-1.14.jar into a single fat Jar using ANT was causing this exception. changing the packaging to use MVN has fixed the problem

    <?xml version="1.0"?>
    <project
      xmlns="http://maven.apache.org/POM/4.0.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.clintel.java_fop</groupId>
      <artifactId>java_fop</artifactId>
      <version>develop</version>
      <name>java_fop</name>
      <url>http://maven.apache.org</url>
      <packaging>jar</packaging>
      <repositories>
        <repository>
          <id>Sonatype-public</id>
          <name>SnakeYAML repository</name>
          <url>https://oss.sonatype.org/content/groups/public/</url>
        </repository>
      </repositories>
      <dependencies>
        <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
        <dependency>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
          <version>1.0.4</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.github.jtidy/jtidy -->
        <dependency>
          <groupId>com.github.jtidy</groupId>
          <artifactId>jtidy</artifactId>
          <version>1.0.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/xalan/serializer -->
        <dependency>
          <groupId>xalan</groupId>
          <artifactId>serializer</artifactId>
          <version>2.7.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/xalan/xalan -->
        <dependency>
          <groupId>xalan</groupId>
          <artifactId>xalan</artifactId>
          <version>2.7.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/xerces/xercesImpl -->
        <dependency>
          <groupId>xerces</groupId>
          <artifactId>xercesImpl</artifactId>
          <version>2.12.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.xmlgraphics/xmlgraphics-commons -->
        <dependency>
          <groupId>org.apache.xmlgraphics</groupId>
          <artifactId>xmlgraphics-commons</artifactId>
          <version>2.6</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-all -->
        <dependency>
          <groupId>org.apache.xmlgraphics</groupId>
          <artifactId>batik-all</artifactId>
          <version>1.14</version>
          <type>pom</type>
        </dependency>
        <!-- https://mvnrepository.com/artifact/xml-apis/xml-apis -->
        <dependency>
          <groupId>xml-apis</groupId>
          <artifactId>xml-apis</artifactId>
          <version>1.4.01</version>
        </dependency>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.13.2</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>org.apache.xmlgraphics</groupId>
          <artifactId>fop</artifactId>
          <version>2.6</version>
        </dependency>
        <dependency>
          <groupId>com.github.jnr</groupId>
          <artifactId>jnr-posix</artifactId>
          <version>3.0.15</version>
        </dependency>
      </dependencies>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
              <compilerVersion>1.8</compilerVersion>
            </configuration>
          </plugin>
          <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-shade-plugin</artifactId>
              <executions>
                  <execution>
                      <goals>
                          <goal>shade</goal>
                      </goals>
                      <configuration>
                          <shadedArtifactAttached>true</shadedArtifactAttached>
                          <transformers>
                              <transformer implementation=
                                "org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                  <mainClass>embedding.FopXml2Pdf</mainClass>
                          </transformer>
                      </transformers>
                  </configuration>
                  </execution>
              </executions>
          </plugin>
        </plugins>
      </build>
    </project>