Document Toolkit and Caching (original) (raw)

Summary

A large portion of the Document class library requires the use of a cache system.

Each LEADDocument object contains an ID. The ID is a unique string value that can be generated automatically by the system (using a GUID generator) or provided by the user and stored in the Document.DocumentId field. The ID is all that is required to re-construct a document object from a cache using LoadFromCache.

Use LoadFromUri to create a LEADDocument object that represents a document such as a PDF, TIFF, or DOCX document stored in a remote URL. The LEADDocument is a data structure containing properties such as the mime type, number of pages, size of each page, and other metadata. It does not contain any of the actual image, SVG, or text data of the pages. The original document data (the PDF, TIFF, or DOCX image) is still stored in the remote URL. This data structure is all that is saved into the cache (by default), and therefore saving and then re-loading a document from the cache is a very fast operation that does not require a large amount of memory. When the user requests an image representation of a page, the document parses it from the original data. This data can also be cached, if required, as explained in the "Cache Workflow" section below.

To use caching, an object that implements ObjectCache is initialized once at the start of the application, and then passed to the DocumentFactory and LEADDocument methods that require caching. Any cache system that can persist data between application re-starts can be used. Refer to the "Cache System Examples" section below for more information.

Generally, the cache is used in one of two ways, depending on the type of the application:

These types of applications usually store a policy setting in the web.config as well. This will control how long to store items in the cache before they expire.

Cache Workflow

Cache workflow describes how the LEADTOOLS Document Web Service uses the cache. The service ships with full source code and the process can be modified as needed. The project source code is located at:

.NET Framework: [Your installation folder]\Examples\Document\JS\DocumentServiceDotNet\fx

.NET Core: [Your installation folder]\Examples\Document\JS\DocumentServiceDotNet\core

Java: [Your installation folder]\Examples\Document\JS\DocumentServiceJava

The JavaScript client demo is located at

JavaScript: [Your installation folder]\Examples\Viewers\JS\DocumentViewerDemo\site

TypeScript: [Your installation folder]\Examples\Viewers\JS\DocumentViewerDemo\ts

Application_Start

The global cache object is created and stored in the static _cache variable (accessible to the rest of the service code through the ServiceHelper.Cache static property). In the sample implementation, this is a LEADTOOLSFileCache object that stores cache items in the file system (local or as recommended: remote UNC).

The cache eviction policy to determine how long items are kept in the cache is also set up here.

The cache is a persistence system, which means that when the system is restarted, only the cache object is re-created and any non-expired items stored in the cache from previous sessions will still be available.

You can ignore the source code dealing with "Pre-Cache". This deals with special code to pre-cache the LEADTOOLS sample documents used in the demo.

The service can be modified to include:

FactoryController.LoadFromUri

The LoadFromUri is the entry point where the user loads a new document located in a remote URL. The document can be any file format supported by LEADTOOLS such as PDF, TIFF, DOCX, PNG, XLSX and countless others. It is invoked from the JavaScriptDocument Viewer client using the "Open URL" menu item.

Ignore the "Pre-Cache" source code to deal with the sample LEADTOOLS documents used by the demo.

DocumentFactory.LoadFromUri is called, passing the cache object that we previously created and the URL requested by the user in LoadDocumentOptions. This method will quickly determine whether the data in the URL contains valid image or document data that is supported, parse the data to determine the number of pages and size of each page, and return a new LEADDocument object containing the information.

Each new LEADDocument object requires a unique ID. Therefore, if the user did not pass one inLoadDocumentOptions.DocumentId (the value is null), then a new one is created by a GUID generator. If the user wishes to use their own ID, the same value is used and it is up to the user to guarantee the uniqueness of this ID. This ID is stored in the Document.DocumentId property of the created object.

Document.CacheUri is checked and if null, is set to a value that can be used to obtain the original document data. Refer to the "Under the Hood" section below for more information.

The following properties of the document are set:

For now, think of this as a single operation and a single item although in reality multiple items are saved into the cache and the original document data (PDF, DOCX, TIFF) may be stored in the cache as well. This is explained in detail in the "Under the Hood" section below.

The JavaScript code will create an instance of JS LEADDocument object from the JSON data and set it in the viewer. The viewer has all the information needed to construct the skeleton required to view the document. Page holders with correct size in the view and thumbnails area, the bookmarks tab if supported and annotation containers. All are created but with empty data since the LEADDocument object does not contain any. The viewer is fully functional and the user can scroll and click on items that will trigger calls to other methods in the service to obtain the required data.

Multi-user systems that will share the same document ID between different browsers can change the value ofDocument.CacheOptions from the default of DocumentCacheOptions.Noneto store page image, SVG and text data into cache and increase performance as explained in the next section.

The service can be modified to include:

PageController Methods

The document is constructed and the first page outline is visible but without content. The system determines that the document supports SVG viewing and requests it by calling the PageController.GetSvg service method with the document ID and page number.

The service will first try to load the document from ServiceHelper.Cache using DocumentFactory.LoadFromCachewith the document ID. This method will only request the small data structure required to re-create the .NET/JavaLEADDocument object and is very fast. As mentioned earlier, this ID is the only value needed to reconstruct the .NET/Java object.

The DocumentPage.GetSvgUrl method is called with the specified options and the resulting SVG data is streamed back to the JavaScript code and the .NET/Java object is disposed.

When the LEADDocument object is constructed from the cache, it will use the same settings forAutoSaveToCache and AutoDeleteFromCache, therefore, the document will not save itself back into the cache upon disposal. PageController.GetSvg is considered a read-only method that does not modify the state of the cache object.

The DocumentViewer will generally only call this method a single time per page and rely on the browser's own caching if requested again (since this is an HTTP GET operation). The method may be called again from the same session only when the browser cache is exhausted. This is performed automatically by the web browser and is outside the control of LEADTOOLS.

The value of Document.CacheOptions is set to DocumentCacheOptions.None, meaning that only the parts required to reconstruct the document is saved into the cache and page image, SVG and text data are not. This is used to minimize cache size since in almost all cases, the DocumentViewer will never call PageController.GetSvg for a page more than once and the resulting SVG data (which can be large) is never requested from the server again.

Multi-user systems that will share the same document ID between different browsers can change the value ofDocument.CacheOptions from the default value of DocumentCacheOptions.Noneto store page image, SVG and text data into cache to increase performance. For instance, setting the value toAll (includes PageSvg) during FactoryController.LoadFromUri above beforeSaveToCache will instruct the library to store the page data into the cache upon request. The workflow for DocumentPage.GetSvgUrl is as follows:

  1. Always: check whether the cache contains data for the key "documentID" + "value_of_pageNumber" + "svg". If found, return it. Naturally, the first time this method is called for this page, it will not find any data and will go to step 2.
  2. Extract the SVG data for the page from the original document PDF, DOCX, etc. data. This is almost always a more expensive operation than returning the data directly from the cache.
  3. If Document.CacheOptions of the owner document contains PageSvg, then store the SVG data into the cache using the key above.
  4. Return the SVG data

Thereafter, subsequent calls from other user sessions (or browsers) to obtain the SVG data for the same document and same page will find the data in the cache at the first step and will never extract the data from the original document again.

The process can reset if the data is evicted from the cache manually or through automatic expiration. When the page SVG key is not found, steps 2-4 will repeat and the data is re-generated when it is requested the next time.

The service can be modified to include:

Other Page and DocumentController methods

The other methods of the Page and Document controllers work in a fashion similar to PageController.GetSvg. The document is loaded from the cache, the data is extracted using the .NET/Java LEADDocument object and returned to JavaScript.

The following methods will re-save the LEADDocument object into the cache because they modify the data:

  1. FactoryController.Decrypt - sets the password required to read encrypted documents
  2. PageController.SetAnnotations - saves annotations modified by the user (in preparation to converting the document to other formats)
  3. FactoryController.SaveToCache - saves new or updated virtual documents created through JavaScript into the cache.

Under the Hood

When DocumentFactory.SaveToCache is called, the items below are stored in the cache. Calling DocumentFactory.LoadFromCache will succeed if all the values are found in the cache.

This is performed by calling ObjectCache.AddOrGetExisting with regionNameequal to the documentID (Document.DocumentId) and key equal to the value described in the table below. These cache items are always in the cache for a document to be re-constructed (DocumentFactory.LoadFromCache). If the cache system does not support regions (or groups), then it can simply concatenate the value of regionName (the document ID) + key to create a unique cache ID. See the "Caches System Examples" section below.

The original document data (PDF, DOCX, TIFF) is required to parse the document page data after it has been loaded from the cache. The data is stored in the "DownloadedFile_CacheId" key described below and the value depends on whether the cache system supports external resources.

If client-side PDF rendering support is used with the Document Service, then direct HTTP access to the original image data is required and must be set in Document.CacheUri JavaScript object. The PDF renderer will use this value to obtain the original data and render the PDF pages directly into the viewer surface and DocumentPage.GetSvgUrl and DocumentPage.GetImageUrl are never called.

The .NET/Java DocumentFactory.LoadFromUri method will not set the value of Document.CacheUri and leave it to the default value of null prior to returning it to JavaScript. The JavaScript DocumentFactory.LoadFromUri method will check if the for value is null and will then replace it the HTTP GET URL required to call the service CacheController.GetDocumentData web method. Refer to source code in the service for more information.

This is the default implementation of the .NET/Java Document Service for the following reasons:

Alternatively, if using a cache system that stores the items in a virtual directory, such as the LEADTOOLS FileCache, then FileCache.CacheVirtualDirectory can be set to the full virtual directory path of the cache items and the .NET/Java DocumentFactory.LoadFromUri will set Document.CacheUri to the path of the document original data. Finally, the JavaScript DocumentFactory.LoadFromUri method will check for this value, and will not modify it since it is not null.

All possible cache IDs for a document can be obtained through Document.GetCacheKeys.

When a document is deleted from the cache using DocumentFactory.DeleteFromCache, the cache checks whether the system contains DefaultCacheCapabilities.CacheRegions.

The following cache items are added to the cache, depending on DocumentCacheOptions. The format is:

String key = pageId + "_" + itemName

Where pageId is a GUID representing the page.

Key Data Used when Notes
"thumbnailImage" RasterImage containing the thumbnail of this page DocumentCacheOptions.PageThumbnailImage is set Try to get and set during DocumentPage.GetThumbnail
"text" DocumentPageText serializer DocumentCacheOptions.PageText is set Try to get and set during DocumentPage.GetText
"annotations" String containing the XML representation of the annotations container for the page DocumentCacheOptions.PageAnnotations is set Try to get and set during DocumentPage.GetAnnotations
"image_[number]" number is 0,1,2 or 4 depending on the value of Document.Images.MaximumImagePixelSize RasterImage containing the image of this page DocumentCacheOptions.PageImage is set Try to get and set during DocumentPage.GetImage
"svgBackImage_[number]" number is 0,1,2 or 4 depending on the value of Document.Images.MaximumImagePixelSize RasterImage containing the image of this page DocumentCacheOptions.PageSvgBackImage is set Try to get and set during DocumentPage.GetSvgBackImage
"svg_[number1]_[number2]" number1 can be either 0 or 1 (depending on whether this SVG is to be used for viewing or conversion). number2 can be 0,1,2,3 and up to 15 similar to the images above SvgDocument containing the SVG representation of this page DocumentCacheOptions.PageSvg is set Try to get and set during DocumentPage.GetSvg

Cache System Examples

ObjectCache is an abstract class. Derived object can be implemented to add support for caching using external systems. Below are sample implementations.

FileCache

FileCache is the default implementation of ObjectCache. It supports regions, external resources and virtual directories.

MemoryCache Example

The MemoryCache example shows a simple in-memory cache implementation showing the basics of custom caching. It should not be used in a production environment.

RedisObjectCache Example

The RedisObjectCache example shows an implementation of an Azure Redis Cache to be used with the LEADTOOLS Document Library.

RedisWithBlobsObjectCache Example

The RedisWithBlobsObjectCache example shows an implementation of Azure Redis Cache and Storage Blobs to be used with the LEADTOOLS Document Library.

Ehcache Example

The EhcacheObjectCache examples show an implementation of the popular Java Ehcache system to be used with the LEADTOOLS Document Library.

See Also

Document Library Features

Document Viewer Application

Loading Documents Using LEADTOOLS Document Library

Creating Documents with LEADTOOLS Document Library

Uploading Using the Document Library

Document Library Coordinate System

Loading Encrypted Files Using the Document Library

Parsing Text with the Document Library

Barcode processing with the Document Library

Using jQuery Promises in the Document Library

Loading Images in the Document Library

Document Page Transformation

Using LEADTOOLS Document Viewer

Status Document Job Converter

Document View and Convert Redaction