Swift

Architecture

A schematic diagram of Genero Report Writer for Swift

Scalability

A schematic diagram illustrating the distributed nature of Genero Report Writer for Swift

Highlights

Detailed feature overview

Customizing the presentation

  • Easy to use, WYSIWYG editor,
  • Schema based, type-safe editing
  • Avoids run-time errors caused by failing string conversions,
  • Compile-time impact analysis,
  • Lists issues in a report design caused by changes to the schema. This feature is of  particular importance for end users that have customized or created their own report designs. Upon receipt of a software update they can check their reports against the new schemas shipped with the update to detect and fix any issues before making the update operational,
  • Batch upgrades.  A command line tool is available to perform batch upgrades of report design files from one version of the software to another,
  • Batch updates and software-assisted issue resolution in the report designer. A command line tool is available to update the report design files in cases where the schemas may have changed (e.g. during an application update and the end user’s site). The update algorithm is optimal in the sense that it finds a minimal patch so that in the general case no manual intervention is required. In the rare case that parts of a schema have been removed or renamed users are assisted in resolving the issues in form of issue list that is persistently stored with the report design file until all issues have been resolved.

Data production and presentation separated

  • Data stream and document formatting are separate,
  • Multiple presentations per data source,
  • Defines a clear interface between application vendors who are responsible for providing the data sources and their associated schemas and users who customize or add presentations to them.

Structured data source

  • Process level interface as opposed to accessing the database directly,
  • Less sensitive to database changes. Process level messages shield users from details of the database and allow application vendors to change the database schema without breaking customized or self made reports,
  • Prevents replication of business rules in report designs. By accessing “cooked” data, users are shielded from the need to know details on how things are stored in the database. It avoids the replication of central business logic in the report designs (e.g. rules about which address is actually used as a billing address of an invoice when there are multiple choices in the database),
  • Support for structured data as opposed to flat record sets returned by SQL queries. The data behind sophisticated reports such as invoices or delivery can rarely be represented as a flat list of records. The natural representation is a structured message allowing for arbitrary nested lists of different records. Using “sub reports” as in many ad hoc reporting tools is not an adequate solution since it adds unnecessary complexity and typically reverses the network communication causing performance problems due to network latency,
  • Novel, serial, graphical matching and transformation language. Conceptually similar to XSL-T, the RTL transformation language is limited in the type of transformations it can do (e.g. no recursion), but can be represented graphically. It works for documents of arbitrary size.

Performance & scalability

  • Single pass, unidirectional processing pipe. Since network latency can be regarded as a resource that does not scale it is important to avoid reversing the communication direction during a job. The engine can be used in a distributed environment with very high roundtrip times and low bandwidth without noticeable decrease in performance,
  • Serial processing of arbitrarily sized documents.
    • Thousands of pages, low and constant memory,
    • Distributed processing and multiple server option. The multi tier option allows to offload the report rendering to one or more separate machines leaving only the data source message creation for the server.

Sophisticated layout engine

  • Pixel exact positioning,
  • Relative positioning vertical and horizontal,
  • Content propagation vertical and horizontal,
  • Multicolumn layout,
  • Tabular layout,
  • Pivot tables,
  •  Sub-reports,
  • Sophisticated headers and footers,
  • Sophisticated page breaking,
  • Label printing on varying media. The report design contains the description of a single label abstracting from the actual layout on the media removing the need to change the report design for different label printers or different label sheets,
  • Running totals in headers and footers,
  • Page n of m in headers and footers while retaining serial processing,
  • Self-layouting business graphs,
  • Large number of natively implemented bar codes,
  • Bitmap and SVG images. The lean scalable vector graphics (also those of other origin such as bar codes and business graphics) are preserved in all formats that support vector drawing such as PDF, browser or printer output. In all other formats they are rendered into bitmaps.

APIs

  • Design time API
    • API for schema introspection,
    • API for report design file introspection and generation,
    • API for template based report design generation,
    • API for pivot table configuration.
  • Run time API
    • Data level API,
      • Selection of source,
      • Configuration of localization,
      • Recommend JAXB for schema generation and marshalling,
    • Document level API,
      • Selection of design,
      • Configuration of page characteristics,
      • Configuration of label layout,
    • Device level API
      • Selection of device (e.g. PDF, server printer, client printer, ..),
      • Device specific configuration (e.g. Paper tray selection of printer).

Report viewers and devices

  • Browser based report viewer
    • Low band-width,
    • 100% pixel exact rendering,
    • Uses cacheable WOFF fonts and SVG vector graphics,
    • Streaming capable for immediate rendering of huge reports,
    • Fast, random navigation in huge documents,
    • Bookmarkable and shareable reports
  • Native report viewer
    • Very fast processing, low, nearly fixed memory consumption,
    • 100% pixel exact rendering using embedded fonts,
    • Streaming capable for immediate rendering of huge reports,
    • Fast, random navigation in huge documents,
    • Support for silent printing
      • Viewer not visible,
      • Selecting printer via server API,
      • Configuration of printer via server API (e.g. selecting paper source),
  • Server side printing
    • Serial processing if supported by the operating system,
    • Programmatic control via IPP properties
  • File generation
    • PDF,
    • RTF (MS-Word),
    • XLS/XLSX (MS-Excel),
    • Postscript,
    • SVG

Run time localization

  • Single design for multiple languages. Primitives are provided to translate strings and format data in locale specific manner individually per document at runtime. Layouts can be defined that handle the resulting differences in text size well.
  • Asian language and alternative writing modes support.
  • Efficient handling of Asian fonts.

Templates

  • Support for self written document templates,
  • Type-safe unrolling of field lists and placeholders,
  • Support for complexly structured data sources.

Maintenance

  • Human readable and version controllable file formats,
  • Type safe report design editing,
  • Compile time impact analysis after changed to data sources,
  • Sophisticated report design upgrade algorithm (Similar to diff/patch).
    • 100 % tolerant to addition of fields and structures,
    • Good tolerance to removal,
    • Reports conflicts and allows for manual correction.

Data source generation

  • Graphical data source generator,
  • Creation of code for XML generation,
  • Creation of schema,
  • Type-safe unrolling of field lists and placeholders,
  • Support for complexly structured data sources.

Database support

All of the industry’s leading databases are supported:

  • DB2
  • Informix
  • MS SQL Server
  • MySQL
  • Oracle
  • PostrgreSQL

Getting started

Schema written by hand

Graphical reports are designed based on a XML schema that matches the data to be serialized.
Write your schema by hand.

The schema for the sample program reads as follows:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="sales" type="sales"></xs:element>
    <xs:complexType name="sales">
        <xs:sequence>
            <xs:element name="shopName" type="xs:string" nillable="true"></xs:element>
            <xs:element name="zipCode" type="xs:int"></xs:element>
            <xs:element name="day" type="xs:dateTime" nillable="true"></xs:element>
            <xs:element name="items" type="salesItem" nillable="true" minOccurs="0" maxOccurs="unbounded"></xs:element>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="salesItem">
        <xs:sequence>
            <xs:element name="articleName" type="xs:string" nillable="true"></xs:element>
            <xs:element name="category" type="category" nillable="true"></xs:element>
            <xs:element name="price" type="xs:double"></xs:element>
            <xs:element name="runningTotal" type="xs:double"></xs:element>
        </xs:sequence>
    </xs:complexType>
    <xs:simpleType name="category">
        <xs:restriction base="xs:string">
        <xs:enumeration value="Furniture"></xs:enumeration>
        <xs:enumeration value="Art"></xs:enumeration>
        <xs:enumeration value="Supplies"></xs:enumeration>
        <xs:enumeration value="Travelling"></xs:enumeration>
    </xs:restriction>
    </xs:simpleType> 
</xs:schema>


Design report from schema

Design the report using Report Designer. Choose your report template, associate the triggers and populate the report with data picked from the data view.

The image below shows “SalesList.4rp” created in the Report Designer:

saleslist.4rp

Run report

Select report design

if CommandLine.argc == 1 {
    designFile = "SalesList.4rp"
} else {
    designFile = CommandLine.arguments[1]
}

Configure the output
Select PDF output

selectDevice (rcPtr, PDF)

Serialize model

let reportLauncher = Sales(content_handler, "Columbus Arts", 75038, Date())

Find below the complete listing of the SWIFT program:

/*
 * FOURJS_START_COPYRIGHT(U,2016)
 * Property of Four Js*
 * (c) Copyright Four Js 2016, 2017. All Rights Reserved.
 * * Trademark of Four Js Development Tools Europe Ltd
 *   in the United States and elsewhere
 *
 * Four Js and its suppliers do not warrant or guarantee that these samples are
 * accurate and suitable for your purposes.
 * Their inclusion is purely for information purposes only.
 * FOURJS_END_COPYRIGHT
 */

import Foundation
import libgre
import AppKit

public class Sales
{
    public var content_handler: UnsafeMutablePointer

    var shopName: String?
    var zipCode: Int
    var day: Date?
    var items = [SalesItem]()

    public init?(_ content_handler: UnsafeMutablePointer,
                    _ shopName: String?,
                    _ zipCode: Int,
                    _ day: Date?)
    {
        self.content_handler = content_handler

        self.shopName = shopName
        self.zipCode = zipCode
        self.day = day

        self.items.append(SalesItem("Tablelamp", SalesItem.Category.Furniture, 23.00, nil));
        self.items.append(SalesItem("Tablelamp", SalesItem.Category.Furniture, 267.00, self.items.last));
        self.items.append(SalesItem("Officechair", SalesItem.Category.Furniture, 155.00, self.items.last));
        self.items.append(SalesItem("Grandfather clock", SalesItem.Category.Furniture, 329.00, self.items.last));
        self.items.append(SalesItem("Scissors", SalesItem.Category.Supplies, 19.00, self.items.last));
        self.items.append(SalesItem("Measuring tape", SalesItem.Category.Supplies, 23.00, self.items.last));
        self.items.append(SalesItem("Sunglasses", SalesItem.Category.Travelling, 15.95, self.items.last));
        self.items.append(SalesItem("Penknife", SalesItem.Category.Travelling, 6.25, self.items.last));
        self.items.append(SalesItem("Ornateangel", SalesItem.Category.Art, 1.95, self.items.last));

        self.serializeToXML()
    }

    public func serializeToXML()
    {
        startElement(content_handler, "sales")

        addElement(content_handler, "shopName", shopName)
        addElement(content_handler, "zipCode", "\(zipCode)")
        addElement(content_handler, "day", (day == nil ? nil : "\(day!)"))

        for item in items
        {
            item.serializeToXML(content_handler)
        }

        endElement(content_handler, "sales")
    }

    class SalesItem
    {
        enum Category: String {
            case Furniture, Art, Supplies, Travelling
        }

        var articleName: String?
        var category: Category?
        var price: Double
        var runningTotal: Double

        // The previous item is passed to allow computing the running total.
        init(_ articleName: String?, _ category: Category?, _ price: Double, _ previousItem: SalesItem?)
        {
            self.articleName = articleName
            self.category = category
            self.price = price

            self.runningTotal = (previousItem == nil ? price : previousItem!.runningTotal + price)
        }

        func serializeToXML(_ content_handler: UnsafeMutablePointer)
        {
            startElement(content_handler, "items")

            addElement(content_handler, "articleName", articleName)
            addElement(content_handler, "category", (category == nil ? nil : category!.rawValue))
            addElement(content_handler, "price", "\(price)")
            addElement(content_handler, "runningTotal", "\(runningTotal)")

            endElement(content_handler, "items")
        }
    }
}

public func addElement(_ content_handler: UnsafeMutablePointer, _ name: String, _ content: String?)
{
    if (content == nil)
    {
        startElement(content_handler, name)
        attribute(content_handler, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
        attribute(content_handler, "xsi:nil", "true")
        endElement (content_handler, name)    }
    else
    {
        startElement(content_handler, name)
        characters(content_handler, content!)
        endElement (content_handler, name)
    }
}

/**
 * MAIN
 *
 *  Runs the report using the design file specified in args[0] or "SalesList.4rp" otherwise.
 *  The program creates the file "SalesList.pdf" and opens it using
 *  NSWorkspace.shared().open() which will typically
 *  invoke the Preview application.
 */

var designFile: String
var outputFilename: String = "SalesList.pdf"

if CommandLine.argc == 1 {
    designFile = "SalesList.4rp"
} else {
    designFile = CommandLine.arguments[1]
}

let rcPtr = createRuntimeConfiguration(designFile)
setOutputFileName(rcPtr, outputFilename)
selectDevice (rcPtr, PDF)
configureDistributedProcessing(rcPtr, "127.0.0.1", 7000)
guard let content_handler = createContentHandler(rcPtr) else {
    print("Info: Report Writer server may not be started. Launch it with the following command: greportwriter -l 7000")
    exit(EXIT_FAILURE)
}

let reportLauncher = Sales(content_handler, "Columbus Arts", 75038, Date())

// Open the file
let reportFileURL = URL(fileURLWithPath: "../" + outputFilename).absoluteURL
guard NSWorkspace.shared().open(reportFileURL) else {
    print("Error opening \(outputFilename).")
    exit(EXIT_FAILURE)
}

exit(EXIT_SUCCESS)

Resulting Report

Executing the above code produces the following PDF document: