Thursday, April 23, 2015

Aspose document generation

Hello,

In today's business world reporting comes out as the end result of the functional application and it serves the purpose of giving introspection into the system, functionality, current and future needs and much more. Having a good system to produce reports is a challenging requirement as one has to balance functionality, requirements, price, potential support needs, easiness of use and widespread acceptance in development community, documentation, performance, interoperability etc. There is a huge potential of various products on the Internet when searching for a suitable framework to satisfy such needs.

During one of my last projects, we needed to accommodate several requirements in finding a product that can do it all :). I believe that we have come across a product that in our testing and POC proved to be a right choice. That product is Aspose.

Aspose is a leading vendor of .NET, Java, Cloud and Android APIs, SharePoint components and rendering extensions for Microsoft SQL Server Reporting Services and JasperReports. They provide various products for working with Word, Excel, Images etc. To make the process easier, Aspose offers a license for all of the products called Total license. The pricing is very competitive too.

The benefit of using the Aspose is that end reports or document templates can be designed by business users in form of Excel of Word document and Aspose can be used to programmatically populate these documents. Documentation is very good with a lot of examples. Support is done primarily through the forums. The response times for support requests at the time I was writing this were very good even for unpaid support.

Usefulness of the Aspose comes from the versatility of the product, in a way that we can for example, start working with Word and add Excel details or pull parts of it, convert and standardize both and produce combined PDF, and then insert images or graphs on the go. Product comes in a form of library and supports both Java and .NET worlds. Library use is straight forward and license is loaded through the code before invocation of the function calls. Documents can be processed from the files or from the streams (if you keep them in the database). Library supports multithreading and in our tests proved to be very consistent and without apparent memory leaks. Data population uses Mail Merge functionality from Word, and supports both plain fields and repeating fields (like tables). Nesting tables require some playing around design in Word documents but it is doable and result looks very good. The product can run in both Windows and *NIX world and having Word or Excel installation in not needed.

I also have to add that libraries can be converted into OSGi friendly libraries and they work quite well in OSGi container too, whether you package them as JAR dependency or expose them as an OSGi bundle.

When working with Aspose and Mail Merge, data stream is established through the java.sql.Statement and has to be passed like this. We have tested functionality on both Oracle and DB2 and both work really well. Minor overriding needs to be done in case of BLOB fields to accommodate output based on the client library that you want to use.

A sample generic application (you can find this code on Aspose site in various sections):

public class AsposeDemoImpl {

    private final static Logger logger = LoggerFactory.getLogger(AsposeDemoImpl.class);

    private DataSource dataSource;

    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public String generateDocument(String document) {
        logger.info("Generate document service is starting");

        Connection connection = null;

        try {
            connection = dataSource.getConnection();

            Document doc = new Document("WordTemplate.docx");

            doc.getMailMerge().setFieldMergingCallback(new HandleMergeOracleClob());

            DataSet dataSet = new DataSet();

            ResultSet resultSet = createStatement().executeQuery(
                    "SELECT * from DUAL"
            );

            DataTable s1 = new DataTable(resultSet, "LogicalNameInTemplate");

            dataSet.getTables().add(s1);
     
            doc.getMailMerge().setCleanupOptions(MailMergeCleanupOptions.REMOVE_UNUSED_REGIONS);

            doc.getMailMerge().executeWithRegions(dataSet);

            resultSet.close();

            doc.save("c:\\Result.docx");
            doc.save("c:\\Result.pdf");

        } catch (Exception e) {
            logger.error(e.toString());
        } finally {
            try {
                if (connection != null && !connection.isClosed())
                    connection.close();
            } catch (SQLException e) {
                logger.error(r.toString());
            }
        }

        return "DONE";
    }

    private Statement createStatement() throws Exception {
        return getDataSource().getConnection().createStatement();
    }

    private Statement createStatementFO() throws Exception {
        return getDataSource().getConnection().createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
    }

    private Statement createStatementSI() throws Exception {
        return getDataSource().getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
    }

    private class HandleMergeOracleClob implements IFieldMergingCallback {

        @Override
        public void fieldMerging(FieldMergingArgs e) throws Exception {
            if ("TEXTFEILD".equalsIgnoreCase(e.getFieldName()) && "TABLE".equalsIgnoreCase(e.getTableName())) {
                //TODO update content with text field - text is retrieved from BLOB
            }
        }

        @Override
        public void imageFieldMerging(ImageFieldMergingArgs e) throws Exception {
            if ("IMAGEFIELD".equalsIgnoreCase(e.getFieldName()) && "TABLE".equalsIgnoreCase(e.getTableName())) {
                //TODO update content with image manipluation - image is retrieved from BLOB
            }
        }
    }
}

1 comment:

  1. Thanks for the clear, well written description of Aspose. I will be working with this product on my new contract and now have a good idea of what it does.

    ReplyDelete