New capabilities of generating file preview

Starting with ELMA 3.11 the file preview generation mechanism has been expanded. To increase the performance and manageability, the file preview generation has been divided into two parts:

  1. An internal ELMA service that manages file preview generation queue, generation start and stop, and interaction with the user;
  2. File preview generators, implemented in the form of .exe files.

Let's take a closer look at this mechanism. To implement the possibility to use 'external' generators, a new file preview generator interface has been added, which is presented below.

{
public interface IFilePreviewCreatorEx : IFilePreviewCreator
        /// <summary>
 
        /// Full name of the file preview generator's executable file
 
        /// </summary>
 
        string ExternalCreatorFileName { get; }
 
  
 
        /// <summary>
 
        /// An external file preview generator is required
 
        /// </summary>
 
        /// <returns><с>true</с>, if an external preview file generator is required</returns>
 
        bool RequiredExternalCreator { get; }
 
  
 
        /// <summary>
 
        /// Create a preview file using an external generator
 
        /// </summary>
 
        /// <param name="filePreviewDir">Path to the preview directory</param>
 
        /// <param name="file">File</param>
 
        /// <returns>External generator process</returns>
 
        Process CreateWithExternalCreator(string filePreviewDir, BinaryFile file);
 
    }

Based on this interface, an extended generator base class has been implemented:

public abstract class BaseFilePreviewCreatorEx : BaseFilePreviewCreator, IFilePreviewCreatorEx 
  {
 
        /// <summary>
 
        /// Full name of the file preview generator's executable file
 
        /// </summary>
 
        public virtual string ExternalCreatorFileName
 
        {
 
            get
 
            {
 
                return string.Empty;
 
            }
 
        }
 
  
 
        /// <summary>
 
        /// An external file preview generator is required
 
        /// </summary>
 
        /// <returns><с>true</с>, if an external file preview generator is required</returns>
 
        public virtual bool RequiredExternalCreator
 
        {
 
            get { return true; }
 
        }
 
  
 
        /// <summary>
 
        /// Create a preview file using an external generator
 
        /// </summary>
 
        /// <param name="filePreviewDir">Path to the preview directory</param>
 
        /// <param name="file">File</param>
 
        /// <returns>External generator process</returns>
 
        public virtual Process CreateWithExternalCreator(string filePreviewDir, BinaryFile file)
 
        {
 
            var packageService = Locator.GetService<PackageService>();
 
  
 
            if (packageService == null)
 
            {
 
                return null;
 
            }
 
            packageService.CheckInitialized();
 
            
 
            var component = packageService.GetComponent("FilePreviewCreator");
 
  
 
            if (component == null)
 
            {
 
                return null;
 
            }
 
  
 
            var documentPath = GetMainFileName(filePreviewDir, file);
 
  
 
            if (ExternalCreatorFileName.IsNullOrEmpty() || documentPath.IsNullOrEmpty() || file.ContentFilePath.IsNullOrEmpty())
 
            {
 
                return null;
 
            }
 
  
 
            var externalCreator = new Process
 
            {
 
                StartInfo =
 
                {
 
                    FileName = Path.Combine(component.ComponentRoot, ExternalCreatorFileName),
 
                    Arguments = string.Format("\"{0}\" \"{1}\"", documentPath, file.ContentFilePath),
 
                    UseShellExecute = false
 
                }
 
            };
 
  
 
            if (externalCreator.Start())
 
            {
 
                return externalCreator;
 
            }
 
  
 
            return null;
 
        }
 
    }
 
}
 

The main function of this base class is Process CreateWithExternalCreator(string filePreviewDir, BinaryFile file), which takes two parameters: filePreviewDir – full path to the directory for saving the generated preview file, file – a file of the document, for which a preview is generated. The returned result points to the 'external' preview generator process.

As you can see from the function code, it starts the generator .exe file and passes two parameters to it via the command prompt: full path to the generated preview file, full path to the file, for which the preview file is generated. Note, that this function is virtual. Thus, when implementing custom preview generators, you can redefine its functions in your implementation of the BaseFilePreviewCreatorEx base class.

ELMA 3.11 features a standard implementation of the preview generation provider, in the form of a separate assembly EleWise.ELMA.FilePreview.LocalService.

Note that EleWise.ELMA.FilePreview.LocalService tracks the server resource usage by external generators, namely the work time (maxTimeWork [s]) and the RAM usage (maxMemoryUsage [Mb]), whose limits are defined in the system configuration file. Exceeding these parameters stops the preview generator process. Below is the standard system configuration file:

<?xml version="1.0"?>
<configuration>
 
                <configSections>
 
                               <section name="main" type="EleWise.ELMA.Configuration.MainBaseSettingsSection, EleWise.ELMA.SDK" />
 
                               <section name="blobStore" type="EleWise.ELMA.Configuration.GenericProviderFeatureSection`1[[EleWise.ELMA.Runtime.Providers.BLOBStoreProviderManager, EleWise.ELMA.SDK]], EleWise.ELMA.SDK" />
 
                               <section name="settingsStore" type="EleWise.ELMA.Configuration.GenericProviderFeatureSection`1[[EleWise.ELMA.Runtime.Providers.SettingsStoreProviderManager, EleWise.ELMA.SDK]], EleWise.ELMA.SDK" />
 
                               <section name="fileStore" type="EleWise.ELMA.Configuration.GenericProviderFeatureSection`1[[EleWise.ELMA.Runtime.Providers.FileStoreProviderManager, EleWise.ELMA.SDK]], EleWise.ELMA.SDK" />
 
    <section name="filePreview" type="EleWise.ELMA.Configuration.GenericProviderFeatureSection`1[[EleWise.ELMA.Files.Previews.FilePreviewServiceProviderManager, EleWise.ELMA.SDK]], EleWise.ELMA.SDK" />
 
                </configSections>
 
                <connectionStrings>
 
                               <add name="MainDB" connectionString="Data Source=localhost; Initial Catalog={CONFIGDIR}\base.fdb; User ID=sysdba; Password=masterkey; Charset=UNICODE_FSS; Dialect=3; ServerType=0" />
 
                </connectionStrings>
 
                <main connectionStringName="MainDB" type="EleWise.ELMA.Extensions.Firebird.FirebirdProvider, EleWise.ELMA.Extensions.Firebird" />
 
                <blobStore defaultProvider="MemoryBLOBStoreProvider">
 
                               <providers>
 
                                               <clear />
 
                                               <add name="MemoryBLOBStoreProvider" type="EleWise.ELMA.Runtime.Providers.MemoryBLOBStoreProvider, EleWise.ELMA.SDK" />
 
                               </providers>
 
                </blobStore>
 
                <settingsStore defaultProvider="NHSettingsProvider">
 
                               <providers>
 
                                               <clear />
 
                                               <add name="NHSettingsProvider" type="EleWise.ELMA.Runtime.Providers.Impl.NHSettingsStoreProvider, EleWise.ELMA.SDK" />
 
                               </providers>
 
                </settingsStore>
 
                <fileStore defaultProvider="FSProvider">
 
                               <providers>
 
                                               <clear />
 
                                               <add name="FSProvider" type="EleWise.ELMA.Runtime.Providers.Impl.FileSystemFileStoreProvider, EleWise.ELMA.SDK" filesPath="Files" />
 
                               </providers>
 
                </fileStore>
 
  <filePreview defaultProvider="FPProvider">
 
    <providers>
 
      <clear />
 
      <add name="FPProvider" type="EleWise.ELMA.FilePreview.LocalService.Services.FilePreviewServiceLocal, EleWise.ELMA.FilePreview.LocalService" maxTimeWork="3600" maxMemoryUsage="500" />
 
    </providers>
 
  </filePreview>
 
</configuration>

The blocks in bold are the ones you need to add to connect your provider implementation.

The second part of the preview generation mechanism consists of external executable generator files, in which the preview file generation logic is implemented for a specific document format.

Let's take a look at a specific implementation of a .txt file preview generator.

First, you need to implement the generator class based on the BaseFilePreviewCreatorEx base class:

/// <summary>
 
    /// Display of text files
 
    /// </summary>
 
    [Component(Order = 100)]
 
    public class TextFilePreviewCreator : BaseFilePreviewCreatorEx
 
    {
 
        public static Guid UID = new Guid("{2C9D21C2-153F-4CD9-B004-84932C602D25}");
 
  
 
        public override Guid Uid
 
        {
 
            get { return UID; }
 
        }
 
  
 
        public override string DisplayName
 
        {
 
            get { return SR.T("Text files (.txt, .xml)"); }
 
        }
 
  
 
        public override List<string> Extensions
 
        {
 
            get { return new List<string> { ".txt", ".xml" }; }
 
        }
 
  
 
        public override string ExternalCreatorFileName
 
        {
 
            get { return "EleWise.ELMA.PreviewCreator.TextFile.exe"; }
 
        }
 
    }
 

As you can see, the ExternalCreatorFileName property must return the external generator file name with its extension - .exe. This file must be run with the following parameters:

  1. Full path to the generated preview file
  2. Ful path to the file, for which the preview is generated

To create an external generator executable file, create a project in MS Visual Studio of the "Console Application" type (fig. 1), with the following structure (fig. 2).

 

Figure 1 – Creating an external preview generator project

  

Figure 2 – External generator project structure

The Nuspec file of your generator should look like this:

<?xml version="1.0"?>
 
<package>
 
  <metadata>
 
    <id>$id$</id>
 
    <title>.txt documents preview generator</title>
 
    <version>$version$</version>
 
    <description>$description$</description>
 
    <authors>$author$</authors>
 
    <tags>[OwnerId:EleWise.ELMA.SDK] [Type:Module] [Component:FilePreviewCreator]</tags>
 
  </metadata>
 
</package>
 

You must specify the FilePreviewCreator component type (highlighted in bold) so that the system package manager placed the external generator to the correct directory when installing the component.

Below is an example of the generator implementation:

namespace EleWise.ELMA.PreviewCreator.WordFile
 
{
 
    class Creator
 
    {
 
        static void Main(string[] args)
 
        {
 
            if (args.Length != 2)
 
            {
 
                return;
 
            }
 
  
 
            string previewFilePath = args[0];
 
            string baseFilePath = args[1];
 
  
 
            using (var writer = new StreamWriter(previewFilePath))
 
            {
 
                using (var reader = new StreamReader(baseFilePath))
 
                {
 
                    var readStr = reader.ReadLine();
 
                    writer.Write("<HTML><BODY>" + readStr + "</BODY></HTML>");
 
                }
 
            }
 
        }
 
    }
 
}