Skip to content

Custom File Specs

Johnson Luong edited this page Jan 14, 2021 · 2 revisions

Harmony Core Logo

Custom File Specs

This document describes the procedure for providing code that will be used to determine data file specs at runtime.

The basic process is to write a class that:

  • Inherits from Harmony.Core.FileIO.FileChannelManager
  • Overrides the GetChannel method
  • Provides a custom value for fileName
  • Calls parent.GetChannel

An example can be found in Harmony.Core.FileIO.HookableFileChannelManager which provides support for adding I/O Hooks classes in a Harmony Core environment.

If you need custom file specs AND I/O hooks, then you should create a custom class in Services and extend Harmony.Core.FileIO.HookableFileChannelManager and follow the same procedure described above.

Having created the custom class, you will need to make it available through dependency injection by adding code in the Startup.ConfigureServicesCustom() partial method, like so: services.AddSingleton<IFileChannelManager, [YourCustomClass]>()

Hooking Channels

By default, all channels are hooked via IOHooks. If you have a scenario where you do not want all operations to be hooked, you can do so with your custom class. You'll need to override the HookChannel method, and return ^null on all operations you do not want to be hooked.

What to do if you need to call remote code for translation

The general guidance here is to not call anything slow as part of opening file channels, this operation is very latency sensitive. Instead it is recommended to produce a translation table using your existing or slightly modified code across traditional bridge. This call should only occur once and translation table should be used for subsequent file channel requests. If you already have a method that can produce this translation table you can cache it using code similar to this.

public class RuntimeFileChannelManager extends FileChannelManager
        
	private BranchLookup, @Lazy<Dictionary<string, string>>
	private TraditionalBridgePool, @ExternalContextPool<ExternalCallContext>
	public method RuntimeFileChannelManager
		tbPool, @ExternalContextPool<ExternalCallContext> ; put your Traditional bridge context here, provided by dependency injection
	proc
		TraditionalBridgePool = tbPool
		BranchLookup = new Lazy<Dictionary<string, string>(LoadBranchLookup)
	endmethod

	private method LoadBranchLookup, @Dictionary<string, string>
	proc
 		data sp = new ServiceCollection().BuildServiceProvider()
		data context = TraditionalBridgePool.MakeContext(sp)
		try
		begin
			data lookupTableTask = context.GetLookupTable()
			lookupTableTask.Wait() ;this call is async and needs to either be waited on or awaited
			mreturn lookupTableTask.Result
		end
		finally
		begin
			TraditionalBridgePool.ReturnContext(context)
		end
 		throw new Exception("shouldnt get here")
	endmethod

	protected override method OpenChannel, int
		fileName, @string
		openMode, FileOpenMode
	proc
		;;use the multi tenant id provider to determine the target branch for this request
		mreturn parent.OpenChannel(BranchLookup.Value[MultiTenantProvider.TenantId] + fileName, openMode)
	endmethod
endclass
Clone this wiki locally