The goal of this exercise is to be able to have the target org tell your package that there is some custom code that needs to be executed. We need a way to do this dynamically, and have it controlled by the target org. That feat can be achieve with a custom setting, an interface class, and dynamic class instantiation.
First, you’ll need to create a non-protected custom setting in your managed package. The custom setting is pretty simple, and contains the following text fields:
- Name - the standard Name field is used to get the values if a specific forking may be needed at specific times.
- ClassName__c - used to hold the name of the external class that needs to be called.
- Namespace__c - used to hold a namespace in case the external class is located in a different extension package.
Now that we have a way for the target org administrator to alert the package code that an external class needs to be called, we need to handle that in the package code itself. We’ll first Create Interface class and a method that is so generic, that it can be used with any number of parameters and can get a response that includes any response type. We do that by setting the return variable and the class parameter to the object data type, which can be casted to any type of other data type. That will allow different implementations to use this class in completely different ways.
Now that the interface class is ready, it can be used in strategic locations around the code to call external classes as needed. If you need some added flexibility and have no fear, you can also blindly execute anything you can find in the custom setting. That can be done by instantiating an instance of the external class by dynamically instantiating the interface class, which provides a concrete type that can be instantiated. Note that you’ll need to make sure that you use the namespace in the forName method if you are pointing to a class in an external package.
The code is now done and a new release of the managed package can be created. The only thing left to do is to use the new code from outside the package. You do that by creating a class in the target org or an extension package that implements the base package interface. Parameters that are sent into this class go by the normal apex rules, so maps and lists that are passed can be manipulated in the external class (passed by reference). Since the interface blueprint is flexible, the implementation can be static in case a callout needs to happen (needs to be static in some cases because a trigger starts the execution).