Configuration and deployment of PDF printing in APEX 4.1.1 using GlassFish 3.1.2 and Apache FOP

Environment: Oracle database 11.2.0.3, APEX 4.1.1, GlassFish 3.1.2 Open Source Edition (Web Profile), Oracle Linux 6.2

Update: Apache FOP support has been deprecated in ORDS 19.2. So please don’t upgrade to ORDS 19.2 (or higher) if you still rely on Apache FOP for PDF generation.

Apache FOP (XSL-FO Processor) can be used together with APEX to allow PDF printing of classic or interactive reports. In this blog post, I will explain how you can deploy and configure FOP in APEX 4.1.1 with GlassFish 3.1.2.

Apache FOP can be installed on a Java application server by deploying the fop.war web archive, which can be found in the /utilities/fop folder inside the APEX installation files. However, the fop.war file does not work out of the box on GlassFish 3.1.2.

I faced two different kind of errors in my installation:

1) package oracle.xml.parser.v2 does not exist: this is because GlassFish can’t find the xmlparserv2.jar file which can be found in $ORACLE_HOME/lib.

2) java.lang.IllegalStateException: getOutputStream() has already been called: this has something to do with getOutputStream() being used more than once; I’m far from a Java specialist, but I found a workaround for this problem on the internet.

This is the solution:

First, we need to extract the original fop.war file (I used the jar utility from my Java 6 JDK installation):

$ /u01/app/java/java6/bin/jar -xf fop.war

You should see the following:

$ ls -la

-rw-r–r– 1 oracle oinstall 1792 May 4 12:44 apex_fop.jsp
-rw-r–r– 1 oracle oinstall 7016135 May 4 12:44 fop.war
drwxr-xr-x 4 oracle oinstall 4096 May 4 14:00 WEB-INF

Next, copy the xmlparserv2.jar file from $ORACLE_HOME/lib into the WEB-INF/lib folder:

$ cp -p /u01/app/oracle/product/11.2.0/db_1/lib/xmlparserv2.jar WEB-INF/lib

Now we need to modify the two apex_fop.jsp files in the top folder and under WEB-INF/classes. Add the following 2 lines just before the final “driver.run();” call:

out.clear();
out = pageContext.pushBody();

The full apex_fop.jsp file should look like this:










Now we are going to recreate the fop.war file:

$ /u01/app/java/java6/bin/jar -cvf fop.war apex_fop.jsp WEB-INF

We are now ready to deploy the fop.war file in GlassFish:

– start up the GlassFish admin console (default: port 4848)

– click on Standalone Instances -> your instance

– click on Applications -> Deploy -> local packaged file… and browse to the “fop.war” file (see screenshot below)

– click on OK; “fop” should now appear in the list of Deployed Applications

After this, you can already test your Apache FOP deployment by opening http://<servername&gt;:<port>/fop/apex_fop.jsp in a web browser. If you see a Java NullPointerException error, things are looking good ;-)

Finally, we need to tell APEX where to find the print server:

– log in to the APEX workspace “internal” with the username “admin”

– click on Manage Instance -> Instance Settings

– fill in the Report Printing part (see screenshot below):

Print Server: External (Apache FOP)
Print Server Host Address: localhost
Print Server Port: (your APEX port)
Print Server Script: /fop/apex_fop.jsp

That’s it! Now try to print a report as PDF in APEX; it should work fine!

 

Matthias

 

 

21 thoughts on “Configuration and deployment of PDF printing in APEX 4.1.1 using GlassFish 3.1.2 and Apache FOP

      • Hi,
        All settings were performed as directed in the post, but did not work is giving the following error when generating printing.

        Error: ORA-20001: The printing engine could not be reached because either the
        URL specified is incorrect or a proxy URL needs to be specified.

        is_internal_error: true
        apex_error_code: APEX.UNHANDLED_ERROR
        ora_sqlcode: -20001

        ora_sqlerrm: ORA-20001: ORA-20001: The printing engine could not be reached because either the
        URL specified is incorrect or a proxy URL needs to be specified.

        error_backtrace:

        ORA-06512: em “APEX_040100.WWV_FLOW_PRINT_UTIL”, line 117
        ORA-06512: em “APEX_040100.WWV_FLOW_RENDER_QUERY”, line 1619
        ORA-06512: em “APEX_040100.WWV_FLOW_RENDER_QUERY”, line 1681
        ORA-06512: em “APEX_040100.WWV_FLOW”, line 7261

        I can not find the solution.
        Can you help me?
        Thanks!

      • Hello Claudio,

        You probably need to give your APEX_040100 user network access, as explained in the APEX 4.1 installation guide. Access to network services is by default disabled in Oracle 11g.

        You can do this by executing the following PL/SQL code with user SYS as SYSDBA:

        DECLARE
        ACL_PATH VARCHAR2(4000);
        ACL_ID RAW(16);
        BEGIN
        -- Look for the ACL currently assigned to '*' and give APEX_040100
        -- the "connect" privilege if APEX_040100 does not have the privilege yet.

        SELECT ACL INTO ACL_PATH FROM DBA_NETWORK_ACLS
        WHERE HOST = '*' AND LOWER_PORT IS NULL AND UPPER_PORT IS NULL;

        -- Before checking the privilege, ensure that the ACL is valid
        -- (for example, does not contain stale references to dropped users).
        -- If it does, the following exception will be raised:
        --
        -- ORA-44416: Invalid ACL: Unresolved principal 'APEX_040100'
        -- ORA-06512: at "XDB.DBMS_XDBZ", line ...
        --
        SELECT SYS_OP_R2O(extractValue(P.RES, '/Resource/XMLRef')) INTO ACL_ID
        FROM XDB.XDB$ACL A, PATH_VIEW P
        WHERE extractValue(P.RES, '/Resource/XMLRef') = REF(A) AND
        EQUALS_PATH(P.RES, ACL_PATH) = 1;

        DBMS_XDBZ.ValidateACL(ACL_ID);
        IF DBMS_NETWORK_ACL_ADMIN.CHECK_PRIVILEGE(ACL_PATH, 'APEX_040100',
        'connect') IS NULL THEN
        DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE(ACL_PATH,
        'APEX_040100', TRUE, 'connect');
        END IF;

        EXCEPTION
        -- When no ACL has been assigned to '*'.
        WHEN NO_DATA_FOUND THEN
        DBMS_NETWORK_ACL_ADMIN.CREATE_ACL('power_users.xml',
        'ACL that lets power users to connect to everywhere',
        'APEX_040100', TRUE, 'connect');
        DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL('power_users.xml','*');
        END;
        /
        COMMIT;

        Let me know if this helps,
        Matthias

  1. Would you be able to provide additional information about the error: Error: ORA-20001: The printing engine could not be reached because either the
    URL specified is incorrect or a proxy URL needs to be specified.? I have verified that I have network access for my user apex_040100. I can get as far as the java null exception, but when I attempt to print a report it states the error above.

    Thanks!

    • That’s strange… Granting network access privileges should get rid of that error. I would think that there is something wrong with your ACL’s…

      What do the following queries return? What version of Oracle database do you use?

      select acl , host , lower_port , upper_port from DBA_NETWORK_ACLS;
      select acl , principal , privilege , is_grant from DBA_NETWORK_ACL_PRIVILEGES;

      Matthias

      • I ran into the same problem and found that the printer port that was set for the APEX instance was wrong. I set it to 8080 and it started working.

        As SYS user:

        SQL> ALTER SESSION SET CURRENT_SCHEMA = APEX_040100;

        To check current printer port setting:

        SQL> SELECT APEX_INSTANCE_ADMIN.GET_PARAMETER(‘PRINT_SVR_PORT’) port from dual;

        PORT
        ——-
        7777

        To change port setting:

        SQL> BEGIN
        APEX_INSTANCE_ADMIN.SET_PARAMETER(‘PRINT_SVR_PORT’, 8080);
        END;
        /

        SQL> commit;

        I also had a problem with “^M” end-of-line characters in the fop.war file. I just did a “dos2unix” command on the files and that fixed the run-time Java error I was getting.

        Other than these two problems that were my fault these instructions worked perfectly. Thanks.

  2. Does this work with custom Report Layouts?

    I tried your setup and printed a report query with a generic layout which worked just fine. With a custom layout though, I get the following error.

    org.w3c.dom.DOMException: NAMESPACE_ERR: An attempt is made to create or change an object in a way which is incorrect with regard to namespaces.
    at com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl.checkDOMNSErr(CoreDocumentImpl.java:2526)

  3. Hello Matthias, i follow this instruccion and when create a pdf file from apex, this file has 1kb and its imposible to open whith acrobat reader.
    Can you help me ?
    Thanks

    • I open de pdf file whith notepad and the error message is “error de informe:
      ORA-20001: No se ha podido acceder al motor de impresión debido a que la dirección URL especificada es incorrecta o a que se debe especificar una dirección URL de proxy.”
      My configuration is
      Print Server : Apache FOP
      Protocol = HTTP
      Direccion = localhost or http://localhost i try with both
      Port: 8080
      Script = /fop/apex_fop.jsp

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.